From d4d2abb313a6727b8702a42b3fa151f079da6525 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Thu, 10 Oct 2024 11:49:02 +0100 Subject: [PATCH 001/335] Use Codama v1.0.0 (#8) See https://github.com/codama-idl/codama/pull/234 --- clients/js/src/generated/accounts/index.ts | 6 +- clients/js/src/generated/accounts/mint.ts | 6 +- clients/js/src/generated/accounts/multisig.ts | 6 +- clients/js/src/generated/accounts/token.ts | 6 +- .../src/generated/errors/associatedToken.ts | 6 +- clients/js/src/generated/errors/index.ts | 6 +- clients/js/src/generated/errors/token.ts | 6 +- clients/js/src/generated/index.ts | 6 +- .../instructions/amountToUiAmount.ts | 6 +- .../js/src/generated/instructions/approve.ts | 6 +- .../generated/instructions/approveChecked.ts | 6 +- clients/js/src/generated/instructions/burn.ts | 6 +- .../src/generated/instructions/burnChecked.ts | 6 +- .../generated/instructions/closeAccount.ts | 6 +- .../instructions/createAssociatedToken.ts | 6 +- .../createAssociatedTokenIdempotent.ts | 6 +- .../generated/instructions/freezeAccount.ts | 6 +- .../instructions/getAccountDataSize.ts | 6 +- .../js/src/generated/instructions/index.ts | 6 +- .../instructions/initializeAccount.ts | 6 +- .../instructions/initializeAccount2.ts | 6 +- .../instructions/initializeAccount3.ts | 6 +- .../instructions/initializeImmutableOwner.ts | 6 +- .../generated/instructions/initializeMint.ts | 6 +- .../generated/instructions/initializeMint2.ts | 6 +- .../instructions/initializeMultisig.ts | 6 +- .../instructions/initializeMultisig2.ts | 6 +- .../js/src/generated/instructions/mintTo.ts | 6 +- .../generated/instructions/mintToChecked.ts | 6 +- .../recoverNestedAssociatedToken.ts | 6 +- .../js/src/generated/instructions/revoke.ts | 6 +- .../generated/instructions/setAuthority.ts | 6 +- .../src/generated/instructions/syncNative.ts | 6 +- .../src/generated/instructions/thawAccount.ts | 6 +- .../js/src/generated/instructions/transfer.ts | 6 +- .../generated/instructions/transferChecked.ts | 6 +- .../instructions/uiAmountToAmount.ts | 6 +- .../js/src/generated/pdas/associatedToken.ts | 6 +- clients/js/src/generated/pdas/index.ts | 6 +- .../src/generated/programs/associatedToken.ts | 6 +- clients/js/src/generated/programs/index.ts | 6 +- clients/js/src/generated/programs/token.ts | 6 +- clients/js/src/generated/shared/index.ts | 6 +- .../js/src/generated/types/accountState.ts | 6 +- .../js/src/generated/types/authorityType.ts | 6 +- clients/js/src/generated/types/index.ts | 6 +- package.json | 8 +- pnpm-lock.yaml | 160 +++++++++--------- program/idl.json | 4 +- scripts/generate-clients.mjs | 14 +- 50 files changed, 231 insertions(+), 231 deletions(-) diff --git a/clients/js/src/generated/accounts/index.ts b/clients/js/src/generated/accounts/index.ts index 4fc1a10..22eaa0c 100644 --- a/clients/js/src/generated/accounts/index.ts +++ b/clients/js/src/generated/accounts/index.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ export * from './mint'; diff --git a/clients/js/src/generated/accounts/mint.ts b/clients/js/src/generated/accounts/mint.ts index bfe9150..5b173bd 100644 --- a/clients/js/src/generated/accounts/mint.ts +++ b/clients/js/src/generated/accounts/mint.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/accounts/multisig.ts b/clients/js/src/generated/accounts/multisig.ts index 733c905..066bf91 100644 --- a/clients/js/src/generated/accounts/multisig.ts +++ b/clients/js/src/generated/accounts/multisig.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/accounts/token.ts b/clients/js/src/generated/accounts/token.ts index 2e16ca9..278baa0 100644 --- a/clients/js/src/generated/accounts/token.ts +++ b/clients/js/src/generated/accounts/token.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/errors/associatedToken.ts b/clients/js/src/generated/errors/associatedToken.ts index 9c00376..c651725 100644 --- a/clients/js/src/generated/errors/associatedToken.ts +++ b/clients/js/src/generated/errors/associatedToken.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/errors/index.ts b/clients/js/src/generated/errors/index.ts index a646b62..4a8094e 100644 --- a/clients/js/src/generated/errors/index.ts +++ b/clients/js/src/generated/errors/index.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ export * from './associatedToken'; diff --git a/clients/js/src/generated/errors/token.ts b/clients/js/src/generated/errors/token.ts index e921c92..9afda17 100644 --- a/clients/js/src/generated/errors/token.ts +++ b/clients/js/src/generated/errors/token.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/index.ts b/clients/js/src/generated/index.ts index a640c1f..1f8edf1 100644 --- a/clients/js/src/generated/index.ts +++ b/clients/js/src/generated/index.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ export * from './accounts'; diff --git a/clients/js/src/generated/instructions/amountToUiAmount.ts b/clients/js/src/generated/instructions/amountToUiAmount.ts index 0502531..4aa8240 100644 --- a/clients/js/src/generated/instructions/amountToUiAmount.ts +++ b/clients/js/src/generated/instructions/amountToUiAmount.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/approve.ts b/clients/js/src/generated/instructions/approve.ts index b2a7b77..f2deaed 100644 --- a/clients/js/src/generated/instructions/approve.ts +++ b/clients/js/src/generated/instructions/approve.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/approveChecked.ts b/clients/js/src/generated/instructions/approveChecked.ts index 10e761d..1e37bfa 100644 --- a/clients/js/src/generated/instructions/approveChecked.ts +++ b/clients/js/src/generated/instructions/approveChecked.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/burn.ts b/clients/js/src/generated/instructions/burn.ts index 85f8af9..bb15b37 100644 --- a/clients/js/src/generated/instructions/burn.ts +++ b/clients/js/src/generated/instructions/burn.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/burnChecked.ts b/clients/js/src/generated/instructions/burnChecked.ts index 19a54f2..6f137e6 100644 --- a/clients/js/src/generated/instructions/burnChecked.ts +++ b/clients/js/src/generated/instructions/burnChecked.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/closeAccount.ts b/clients/js/src/generated/instructions/closeAccount.ts index b924c78..7973bd4 100644 --- a/clients/js/src/generated/instructions/closeAccount.ts +++ b/clients/js/src/generated/instructions/closeAccount.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/createAssociatedToken.ts b/clients/js/src/generated/instructions/createAssociatedToken.ts index 2a5441d..e24ec53 100644 --- a/clients/js/src/generated/instructions/createAssociatedToken.ts +++ b/clients/js/src/generated/instructions/createAssociatedToken.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/createAssociatedTokenIdempotent.ts b/clients/js/src/generated/instructions/createAssociatedTokenIdempotent.ts index 34e0576..a0216da 100644 --- a/clients/js/src/generated/instructions/createAssociatedTokenIdempotent.ts +++ b/clients/js/src/generated/instructions/createAssociatedTokenIdempotent.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/freezeAccount.ts b/clients/js/src/generated/instructions/freezeAccount.ts index 129f94c..6dfc214 100644 --- a/clients/js/src/generated/instructions/freezeAccount.ts +++ b/clients/js/src/generated/instructions/freezeAccount.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/getAccountDataSize.ts b/clients/js/src/generated/instructions/getAccountDataSize.ts index 0f5d46d..098aee0 100644 --- a/clients/js/src/generated/instructions/getAccountDataSize.ts +++ b/clients/js/src/generated/instructions/getAccountDataSize.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/index.ts b/clients/js/src/generated/instructions/index.ts index fbda370..6011a9d 100644 --- a/clients/js/src/generated/instructions/index.ts +++ b/clients/js/src/generated/instructions/index.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ export * from './amountToUiAmount'; diff --git a/clients/js/src/generated/instructions/initializeAccount.ts b/clients/js/src/generated/instructions/initializeAccount.ts index d64801a..8ea41c8 100644 --- a/clients/js/src/generated/instructions/initializeAccount.ts +++ b/clients/js/src/generated/instructions/initializeAccount.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/initializeAccount2.ts b/clients/js/src/generated/instructions/initializeAccount2.ts index dc9012b..204e0d4 100644 --- a/clients/js/src/generated/instructions/initializeAccount2.ts +++ b/clients/js/src/generated/instructions/initializeAccount2.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/initializeAccount3.ts b/clients/js/src/generated/instructions/initializeAccount3.ts index c57eb04..e10ce5a 100644 --- a/clients/js/src/generated/instructions/initializeAccount3.ts +++ b/clients/js/src/generated/instructions/initializeAccount3.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/initializeImmutableOwner.ts b/clients/js/src/generated/instructions/initializeImmutableOwner.ts index 32a0c60..a25d85c 100644 --- a/clients/js/src/generated/instructions/initializeImmutableOwner.ts +++ b/clients/js/src/generated/instructions/initializeImmutableOwner.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/initializeMint.ts b/clients/js/src/generated/instructions/initializeMint.ts index 181ede3..ea070d8 100644 --- a/clients/js/src/generated/instructions/initializeMint.ts +++ b/clients/js/src/generated/instructions/initializeMint.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/initializeMint2.ts b/clients/js/src/generated/instructions/initializeMint2.ts index b65ca98..cc5595f 100644 --- a/clients/js/src/generated/instructions/initializeMint2.ts +++ b/clients/js/src/generated/instructions/initializeMint2.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/initializeMultisig.ts b/clients/js/src/generated/instructions/initializeMultisig.ts index cd8195b..032af70 100644 --- a/clients/js/src/generated/instructions/initializeMultisig.ts +++ b/clients/js/src/generated/instructions/initializeMultisig.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/initializeMultisig2.ts b/clients/js/src/generated/instructions/initializeMultisig2.ts index 428707e..54fb35e 100644 --- a/clients/js/src/generated/instructions/initializeMultisig2.ts +++ b/clients/js/src/generated/instructions/initializeMultisig2.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/mintTo.ts b/clients/js/src/generated/instructions/mintTo.ts index 210a89a..a64205b 100644 --- a/clients/js/src/generated/instructions/mintTo.ts +++ b/clients/js/src/generated/instructions/mintTo.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/mintToChecked.ts b/clients/js/src/generated/instructions/mintToChecked.ts index b91bd46..0b0e03b 100644 --- a/clients/js/src/generated/instructions/mintToChecked.ts +++ b/clients/js/src/generated/instructions/mintToChecked.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/recoverNestedAssociatedToken.ts b/clients/js/src/generated/instructions/recoverNestedAssociatedToken.ts index eb3d5bb..bc106ac 100644 --- a/clients/js/src/generated/instructions/recoverNestedAssociatedToken.ts +++ b/clients/js/src/generated/instructions/recoverNestedAssociatedToken.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/revoke.ts b/clients/js/src/generated/instructions/revoke.ts index 46893b9..bc37b6e 100644 --- a/clients/js/src/generated/instructions/revoke.ts +++ b/clients/js/src/generated/instructions/revoke.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/setAuthority.ts b/clients/js/src/generated/instructions/setAuthority.ts index fa13e06..21bbc8d 100644 --- a/clients/js/src/generated/instructions/setAuthority.ts +++ b/clients/js/src/generated/instructions/setAuthority.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/syncNative.ts b/clients/js/src/generated/instructions/syncNative.ts index 1f763f9..b9b6b29 100644 --- a/clients/js/src/generated/instructions/syncNative.ts +++ b/clients/js/src/generated/instructions/syncNative.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/thawAccount.ts b/clients/js/src/generated/instructions/thawAccount.ts index 99681f3..af35469 100644 --- a/clients/js/src/generated/instructions/thawAccount.ts +++ b/clients/js/src/generated/instructions/thawAccount.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/transfer.ts b/clients/js/src/generated/instructions/transfer.ts index a5bea4c..e9b95ed 100644 --- a/clients/js/src/generated/instructions/transfer.ts +++ b/clients/js/src/generated/instructions/transfer.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/transferChecked.ts b/clients/js/src/generated/instructions/transferChecked.ts index 473b4db..44b6fa7 100644 --- a/clients/js/src/generated/instructions/transferChecked.ts +++ b/clients/js/src/generated/instructions/transferChecked.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/instructions/uiAmountToAmount.ts b/clients/js/src/generated/instructions/uiAmountToAmount.ts index c91bcd1..3700571 100644 --- a/clients/js/src/generated/instructions/uiAmountToAmount.ts +++ b/clients/js/src/generated/instructions/uiAmountToAmount.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/pdas/associatedToken.ts b/clients/js/src/generated/pdas/associatedToken.ts index c77e267..f9704a9 100644 --- a/clients/js/src/generated/pdas/associatedToken.ts +++ b/clients/js/src/generated/pdas/associatedToken.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/pdas/index.ts b/clients/js/src/generated/pdas/index.ts index 0208f7a..6cd1010 100644 --- a/clients/js/src/generated/pdas/index.ts +++ b/clients/js/src/generated/pdas/index.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ export * from './associatedToken'; diff --git a/clients/js/src/generated/programs/associatedToken.ts b/clients/js/src/generated/programs/associatedToken.ts index c3d3847..b5efc1c 100644 --- a/clients/js/src/generated/programs/associatedToken.ts +++ b/clients/js/src/generated/programs/associatedToken.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/programs/index.ts b/clients/js/src/generated/programs/index.ts index a646b62..4a8094e 100644 --- a/clients/js/src/generated/programs/index.ts +++ b/clients/js/src/generated/programs/index.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ export * from './associatedToken'; diff --git a/clients/js/src/generated/programs/token.ts b/clients/js/src/generated/programs/token.ts index 1270251..016a2ad 100644 --- a/clients/js/src/generated/programs/token.ts +++ b/clients/js/src/generated/programs/token.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/shared/index.ts b/clients/js/src/generated/shared/index.ts index 278bf59..01a7d93 100644 --- a/clients/js/src/generated/shared/index.ts +++ b/clients/js/src/generated/shared/index.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/types/accountState.ts b/clients/js/src/generated/types/accountState.ts index 51f8401..d113ca4 100644 --- a/clients/js/src/generated/types/accountState.ts +++ b/clients/js/src/generated/types/accountState.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/types/authorityType.ts b/clients/js/src/generated/types/authorityType.ts index 5baedc9..826ae17 100644 --- a/clients/js/src/generated/types/authorityType.ts +++ b/clients/js/src/generated/types/authorityType.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ import { diff --git a/clients/js/src/generated/types/index.ts b/clients/js/src/generated/types/index.ts index 56a9344..8128123 100644 --- a/clients/js/src/generated/types/index.ts +++ b/clients/js/src/generated/types/index.ts @@ -1,9 +1,9 @@ /** - * This code was AUTOGENERATED using the kinobi library. + * This code was AUTOGENERATED using the codama library. * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. + * to add features, then rerun codama to update it. * - * @see https://github.com/kinobi-so/kinobi + * @see https://github.com/codama-idl/codama */ export * from './accountState'; diff --git a/package.json b/package.json index 3298465..abdfaaf 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@ }, "devDependencies": { "@iarna/toml": "^2.2.5", - "@kinobi-so/renderers-js": "^0.21.9", - "@kinobi-so/renderers-rust": "^0.21.7", - "kinobi": "^0.21.5", + "@codama/renderers-js": "^1.0.0", + "@codama/renderers-rust": "^1.0.0", + "codama": "^1.0.0", "typescript": "^5.5.2", "zx": "^7.2.3" }, "packageManager": "pnpm@9.1.0" -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 64e198f..b063c59 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,18 +8,18 @@ importers: .: devDependencies: + '@codama/renderers-js': + specifier: ^1.0.0 + version: 1.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/renderers-rust': + specifier: ^1.0.0 + version: 1.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) '@iarna/toml': specifier: ^2.2.5 version: 2.2.5 - '@kinobi-so/renderers-js': - specifier: ^0.21.9 - version: 0.21.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@kinobi-so/renderers-rust': - specifier: ^0.21.7 - version: 0.21.7(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - kinobi: - specifier: ^0.21.5 - version: 0.21.5 + codama: + specifier: ^1.0.0 + version: 1.0.0 typescript: specifier: ^5.5.2 version: 5.5.3 @@ -29,39 +29,39 @@ importers: packages: - '@iarna/toml@2.2.5': - resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} - - '@kinobi-so/errors@0.21.5': - resolution: {integrity: sha512-IqPMOe0qbmuBI8vux9HU+tvx+SaCVk32g5GnRvYxJh6OmpYOEuJRg02nT2XtYPeYWB2IFKJ1X2AnwTbEz9Vx8Q==} + '@codama/errors@1.0.0': + resolution: {integrity: sha512-XSdkNbCNJukhKO5TFJ5cFP7TfddxZwqHV7N/XyMbZ0meVPN1ymT94/d/9b8R+bvKuflj/SXImv527tGZWz6pGA==} hasBin: true - '@kinobi-so/node-types@0.21.5': - resolution: {integrity: sha512-OKpk08+nTsO25xSZBT+PXpjx2FOHfn7jr0CbnQZ+ulfRa+dr3eSf7zSn+0ipKjG+FFWUUGpizgSkgpTQMjAqLA==} + '@codama/node-types@1.0.0': + resolution: {integrity: sha512-UAc+0jprwHFOqtAPqqA//PkrnlUzuqs+N5E36bHhLV0m5qWMlqrfmPg/ffBwMYFJsLFWsRsisALrqPy7ARkUow==} + + '@codama/nodes-from-anchor@1.0.0': + resolution: {integrity: sha512-urqFOV5K1oKBptgIFFLCPWrUsEeZsonml12ieP26ozX12aglGlN0tsxNsCvxJulRIjUxuONbH6xzv7uKt0xSYQ==} - '@kinobi-so/nodes-from-anchor@0.21.3': - resolution: {integrity: sha512-mar3UeJNx61k77NhucqYIwUXZvC0b6mhLYFksQY0Wz+gCFTWLr8exxB7KmgSycT+XuFNOydpYnEOeMa5lUywBQ==} + '@codama/nodes@1.0.0': + resolution: {integrity: sha512-btcnjDaOpEFvVq3uVzlQK4G2OxxyK3P9HkXw423GZaqYQzeSr1pDdTKjyVyg+QO578CGqIMySVlJ2UAdHVMytw==} - '@kinobi-so/nodes@0.21.5': - resolution: {integrity: sha512-6iu9/GXrVs14olVeUAAw73BK2js7RGefVGHBDF6PKcvw6i0DlxhPkZiNOSpzweaeTmZsowHO7xEJKov0446fbQ==} + '@codama/renderers-core@1.0.0': + resolution: {integrity: sha512-WYvOylIzcR0WOc7GlUvGi5ym8IwmslwyV8zfj7FR646bMqaROirFJc+naGEbZ1lMykOyxcackTKL0eDB7954Qw==} - '@kinobi-so/renderers-core@0.21.3': - resolution: {integrity: sha512-Ow1x0IaRmUlqQUAFTQZpq56wpkB6YKdnpNmfjM8IS/ssgz2IG5Jw3LREvNLvdXwpp/eyjSYOsux2RDFJkERl0g==} + '@codama/renderers-js@1.0.0': + resolution: {integrity: sha512-wi9eqrtLbTM49ELqKqxIgbTaf7xKMWT+HIqj6GN373G0OJnSKwUJPIXAGLO+RCls5DGjDuOE5svuThU0zBkfzA==} - '@kinobi-so/renderers-js@0.21.9': - resolution: {integrity: sha512-ZwN3UIYGZHu1V9TYsCPolVPdScR71r4PrLVVLsxixIxPBhdTMIgUbXK4OqHkzxaR5kn8Ssrvuq6+V2f7XFbVSg==} + '@codama/renderers-rust@1.0.0': + resolution: {integrity: sha512-2z+XN6KCTQFDfE30OQcRo2LW4+9dnYlqs8rSUhKO2YsRiCnOoMu/zrNSqLtjL84T2PAwReRq+vBifcE0zaOuRw==} - '@kinobi-so/renderers-rust@0.21.7': - resolution: {integrity: sha512-SXiUG1C/qL21F3bIeDzFmgLDtVXA53+2BDFaVEOx1tE7W7kcd4TkQGYvNw8o7EHNaa2S9paQB9KjQFyV+DsmqQ==} + '@codama/validators@1.0.0': + resolution: {integrity: sha512-jSfU5IrcGTvcqsJSBSzD3Ochig+hKKg2NKsT/vUfQ4jAw2cQrVUP5f4dMXyX779JYfHLHCwZnBYvgEdgi9gBZQ==} - '@kinobi-so/validators@0.21.5': - resolution: {integrity: sha512-JYZWHgma1TrnjhiUJn5/oYS9XfeirUBhwpuTPDRmRrSiHHv329gjWimzZO2uLAm5S5PgFyhLTz+S6jjxRsdNXg==} + '@codama/visitors-core@1.0.0': + resolution: {integrity: sha512-tDIfURVPf7ZokCFLOpKL6Au0ORiza1sPT4zmRSEjCC7iZp0Vb5K5FrdtUL13Wb+6jNM191e5GUFOmULRoavWug==} - '@kinobi-so/visitors-core@0.21.5': - resolution: {integrity: sha512-qNq9CcDh1P/A0BRR7zEdRpzeWL6ObAowMNWpkxZTT2BKqejK9oKWSh2/gzg6ehcn2Fn/J5DE8bnKZfAlEww95g==} + '@codama/visitors@1.0.0': + resolution: {integrity: sha512-JncE6wRJLxt0imlj+loGH6dLPEMK7ozlv9YjWgCQgUYUI7is66OFwhWP5SFO0iEFlVjtOzZLXVQwoe9LSDz8Gg==} - '@kinobi-so/visitors@0.21.5': - resolution: {integrity: sha512-RCJFaN1Q1f/MQW6PP3Oz0fgNXFVmfUEyErMzPM9CjBi1j2BJzTjff7IzEjbTpG7SbDY91eEyTDcl430ygcDBkA==} + '@iarna/toml@2.2.5': + resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} '@noble/hashes@1.5.0': resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} @@ -137,6 +137,9 @@ packages: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + codama@1.0.0: + resolution: {integrity: sha512-ttJ9n2THpqTD8fP8reec+Y2j4ZTBuonDJk8SiKuS6enZBXd67JF3b+GFKM2S5a0xtxN5Evof5aBlY3JyC+jujQ==} + commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -272,9 +275,6 @@ packages: jsonify@0.0.1: resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} - kinobi@0.21.5: - resolution: {integrity: sha512-1xgN00od8x4tokR1Xuqv5Gbg0Iqo9bzrEvA9o2rm63vXqoW7/C+TN1voPhj1SQE4h2VmpfM3MD1clTUvJK0J2g==} - map-stream@0.1.0: resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} @@ -400,41 +400,39 @@ packages: snapshots: - '@iarna/toml@2.2.5': {} - - '@kinobi-so/errors@0.21.5': + '@codama/errors@1.0.0': dependencies: - '@kinobi-so/node-types': 0.21.5 + '@codama/node-types': 1.0.0 chalk: 5.3.0 commander: 12.1.0 - '@kinobi-so/node-types@0.21.5': {} + '@codama/node-types@1.0.0': {} - '@kinobi-so/nodes-from-anchor@0.21.3': + '@codama/nodes-from-anchor@1.0.0': dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/nodes': 0.21.5 - '@kinobi-so/visitors': 0.21.5 + '@codama/errors': 1.0.0 + '@codama/nodes': 1.0.0 + '@codama/visitors': 1.0.0 '@noble/hashes': 1.5.0 - '@kinobi-so/nodes@0.21.5': + '@codama/nodes@1.0.0': dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/node-types': 0.21.5 + '@codama/errors': 1.0.0 + '@codama/node-types': 1.0.0 - '@kinobi-so/renderers-core@0.21.3': + '@codama/renderers-core@1.0.0': dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/nodes': 0.21.5 - '@kinobi-so/visitors-core': 0.21.5 + '@codama/errors': 1.0.0 + '@codama/nodes': 1.0.0 + '@codama/visitors-core': 1.0.0 - '@kinobi-so/renderers-js@0.21.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@codama/renderers-js@1.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/nodes': 0.21.5 - '@kinobi-so/nodes-from-anchor': 0.21.3 - '@kinobi-so/renderers-core': 0.21.3 - '@kinobi-so/visitors-core': 0.21.5 + '@codama/errors': 1.0.0 + '@codama/nodes': 1.0.0 + '@codama/nodes-from-anchor': 1.0.0 + '@codama/renderers-core': 1.0.0 + '@codama/visitors-core': 1.0.0 '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) nunjucks: 3.2.4 prettier: 3.3.3 @@ -443,12 +441,12 @@ snapshots: - fastestsmallesttextencoderdecoder - typescript - '@kinobi-so/renderers-rust@0.21.7(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@codama/renderers-rust@1.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/nodes': 0.21.5 - '@kinobi-so/renderers-core': 0.21.3 - '@kinobi-so/visitors-core': 0.21.5 + '@codama/errors': 1.0.0 + '@codama/nodes': 1.0.0 + '@codama/renderers-core': 1.0.0 + '@codama/visitors-core': 1.0.0 '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) nunjucks: 3.2.4 transitivePeerDependencies: @@ -456,23 +454,25 @@ snapshots: - fastestsmallesttextencoderdecoder - typescript - '@kinobi-so/validators@0.21.5': + '@codama/validators@1.0.0': dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/nodes': 0.21.5 - '@kinobi-so/visitors-core': 0.21.5 + '@codama/errors': 1.0.0 + '@codama/nodes': 1.0.0 + '@codama/visitors-core': 1.0.0 - '@kinobi-so/visitors-core@0.21.5': + '@codama/visitors-core@1.0.0': dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/nodes': 0.21.5 + '@codama/errors': 1.0.0 + '@codama/nodes': 1.0.0 json-stable-stringify: 1.1.1 - '@kinobi-so/visitors@0.21.5': + '@codama/visitors@1.0.0': dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/nodes': 0.21.5 - '@kinobi-so/visitors-core': 0.21.5 + '@codama/errors': 1.0.0 + '@codama/nodes': 1.0.0 + '@codama/visitors-core': 1.0.0 + + '@iarna/toml@2.2.5': {} '@noble/hashes@1.5.0': {} @@ -550,6 +550,13 @@ snapshots: chalk@5.3.0: {} + codama@1.0.0: + dependencies: + '@codama/errors': 1.0.0 + '@codama/nodes': 1.0.0 + '@codama/validators': 1.0.0 + '@codama/visitors': 1.0.0 + commander@12.1.0: {} commander@5.1.0: {} @@ -690,13 +697,6 @@ snapshots: jsonify@0.0.1: {} - kinobi@0.21.5: - dependencies: - '@kinobi-so/errors': 0.21.5 - '@kinobi-so/nodes': 0.21.5 - '@kinobi-so/validators': 0.21.5 - '@kinobi-so/visitors': 0.21.5 - map-stream@0.1.0: {} merge2@1.4.1: {} diff --git a/program/idl.json b/program/idl.json index be34212..83c8794 100644 --- a/program/idl.json +++ b/program/idl.json @@ -2758,6 +2758,6 @@ "origin": "shank" } ], - "standard": "kinobi", - "version": "0.19.0" + "standard": "codama", + "version": "1.0.0" } diff --git a/scripts/generate-clients.mjs b/scripts/generate-clients.mjs index 80bb37b..da6e849 100644 --- a/scripts/generate-clients.mjs +++ b/scripts/generate-clients.mjs @@ -1,18 +1,18 @@ #!/usr/bin/env zx import 'zx/globals'; -import { createFromRoot } from 'kinobi'; -import { renderVisitor as renderJavaScriptVisitor } from '@kinobi-so/renderers-js'; -// import { renderVisitor as renderRustVisitor } from "@kinobi-so/renderers-rust"; +import { createFromRoot } from 'codama'; +import { renderVisitor as renderJavaScriptVisitor } from '@codama/renderers-js'; +// import { renderVisitor as renderRustVisitor } from "@codama/renderers-rust"; import { workingDirectory } from './utils.mjs'; -// Instanciate Kinobi. -const kinobi = createFromRoot( +// Instanciate Codama. +const codama = createFromRoot( require(path.join(workingDirectory, 'program', 'idl.json')) ); // Render JavaScript. const jsClient = path.join(__dirname, '..', 'clients', 'js'); -kinobi.accept( +codama.accept( renderJavaScriptVisitor(path.join(jsClient, 'src', 'generated'), { prettier: require(path.join(jsClient, '.prettierrc.json')), }) @@ -20,7 +20,7 @@ kinobi.accept( // Render Rust. // const rustClient = path.join(__dirname, "..", "clients", "rust"); -// kinobi.accept( +// codama.accept( // renderRustVisitor(path.join(rustClient, "src", "generated"), { // formatCode: true, // crateFolder: rustClient, From 12a2c97185dd6febc6f7645378f6e7ec9f1f86db Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:33:35 +0000 Subject: [PATCH 002/335] Publish JS client v0.3.2 --- clients/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/js/package.json b/clients/js/package.json index 55b297b..843dc19 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,6 +1,6 @@ { "name": "@solana-program/token", - "version": "0.3.1", + "version": "0.3.2", "description": "JavaScript client for the Token program", "sideEffects": false, "module": "./dist/src/index.mjs", From a32524c0a5762c0679b478205a557da504b5696d Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Thu, 24 Oct 2024 09:10:40 +0100 Subject: [PATCH 003/335] Update from template (#9) --- .github/actions/setup/action.yml | 2 +- clients/js/package.json | 9 ++++++++- clients/js/pnpm-lock.yaml | 12 ------------ package.json | 5 ++++- scripts/client/lint-rust.mjs | 2 +- scripts/client/test-rust.mjs | 5 +++-- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 9c6c869..34e39fe 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -56,7 +56,7 @@ runs: - name: Install Solana if: ${{ inputs.solana == 'true' }} - uses: metaplex-foundation/actions/install-solana@v1 + uses: solana-program/actions/install-solana@v1 with: version: ${{ env.SOLANA_VERSION }} cache: true diff --git a/clients/js/package.json b/clients/js/package.json index 843dc19..eab6a65 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -33,6 +33,14 @@ "registry": "https://registry.npmjs.org" }, "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/solana-program/token.git" + }, + "bugs": { + "url": "https://github.com/solana-program/token/issues" + }, + "homepage": "https://github.com/solana-program/token#readme", "peerDependencies": { "@solana/web3.js": "2.0.0-rc.1" }, @@ -50,7 +58,6 @@ "rimraf": "^5.0.5", "tsup": "^8.1.2", "typedoc": "^0.25.12", - "typedoc-plugin-missing-exports": "^2.2.0", "typescript": "^5.5.3" }, "ava": { diff --git a/clients/js/pnpm-lock.yaml b/clients/js/pnpm-lock.yaml index 21bed93..3b611f1 100644 --- a/clients/js/pnpm-lock.yaml +++ b/clients/js/pnpm-lock.yaml @@ -47,9 +47,6 @@ importers: typedoc: specifier: ^0.25.12 version: 0.25.13(typescript@5.5.3) - typedoc-plugin-missing-exports: - specifier: ^2.2.0 - version: 2.2.0(typedoc@0.25.13(typescript@5.5.3)) typescript: specifier: ^5.5.3 version: 5.5.3 @@ -1871,11 +1868,6 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - typedoc-plugin-missing-exports@2.2.0: - resolution: {integrity: sha512-2+XR1IcyQ5UwXZVJe9NE6HrLmNufT9i5OwoIuuj79VxuA3eYq+Y6itS9rnNV1D7UeQnUSH8kISYD73gHE5zw+w==} - peerDependencies: - typedoc: 0.24.x || 0.25.x - typedoc@0.25.13: resolution: {integrity: sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ==} engines: {node: '>= 16'} @@ -3882,10 +3874,6 @@ snapshots: type-fest@0.20.2: {} - typedoc-plugin-missing-exports@2.2.0(typedoc@0.25.13(typescript@5.5.3)): - dependencies: - typedoc: 0.25.13(typescript@5.5.3) - typedoc@0.25.13(typescript@5.5.3): dependencies: lunr: 2.3.9 diff --git a/package.json b/package.json index abdfaaf..e9eb954 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,15 @@ "template:upgrade": "zx ./scripts/upgrade-template.mjs" }, "devDependencies": { - "@iarna/toml": "^2.2.5", "@codama/renderers-js": "^1.0.0", "@codama/renderers-rust": "^1.0.0", + "@iarna/toml": "^2.2.5", "codama": "^1.0.0", "typescript": "^5.5.2", "zx": "^7.2.3" }, + "engines": { + "node": ">=v20.0.0" + }, "packageManager": "pnpm@9.1.0" } diff --git a/scripts/client/lint-rust.mjs b/scripts/client/lint-rust.mjs index 4cb46bf..0b4a4e6 100644 --- a/scripts/client/lint-rust.mjs +++ b/scripts/client/lint-rust.mjs @@ -12,7 +12,7 @@ import { const lintArgs = cliArguments(); const fix = popArgument(lintArgs, '--fix'); -const toolchain = getToolchainArgument('format'); +const toolchain = getToolchainArgument('lint'); const manifestPath = path.join( workingDirectory, 'clients', diff --git a/scripts/client/test-rust.mjs b/scripts/client/test-rust.mjs index 48e2a30..699acb1 100644 --- a/scripts/client/test-rust.mjs +++ b/scripts/client/test-rust.mjs @@ -7,11 +7,12 @@ import { cliArguments, workingDirectory } from '../utils.mjs'; const testArgs = cliArguments(); const hasSolfmt = await which('solfmt', { nothrow: true }); +const sbfOutDir = path.join(workingDirectory, 'target', 'deploy'); // Run the tests. cd(path.join(workingDirectory, 'clients', 'rust')); if (hasSolfmt) { - await $`cargo test-sbf ${testArgs} 2>&1 | solfmt`; + await $`SBF_OUT_DIR=${sbfOutDir} cargo test --features "test-sbf" ${testArgs} 2>&1 | solfmt`; } else { - await $`cargo test-sbf ${testArgs}`; + await $`SBF_OUT_DIR=${sbfOutDir} cargo test --features "test-sbf" ${testArgs}`; } From 375e4b55bd8173879c1a16f28c08294883b4c099 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 08:14:32 +0000 Subject: [PATCH 004/335] Publish JS client v0.3.3 --- clients/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/js/package.json b/clients/js/package.json index eab6a65..62d9a89 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,6 +1,6 @@ { "name": "@solana-program/token", - "version": "0.3.2", + "version": "0.3.3", "description": "JavaScript client for the Token program", "sideEffects": false, "module": "./dist/src/index.mjs", From 6f5b35608141c02166e1cab6fef68f4024be0f2b Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 5 Nov 2024 18:22:22 +0000 Subject: [PATCH 005/335] Bump web3.js rc version (#10) --- clients/js/package.json | 6 +- clients/js/pnpm-lock.yaml | 592 +++++++++++++++++++++----------------- 2 files changed, 326 insertions(+), 272 deletions(-) diff --git a/clients/js/package.json b/clients/js/package.json index 62d9a89..8ddc010 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -42,13 +42,13 @@ }, "homepage": "https://github.com/solana-program/token#readme", "peerDependencies": { - "@solana/web3.js": "2.0.0-rc.1" + "@solana/web3.js": "2.0.0-rc.4" }, "devDependencies": { "@ava/typescript": "^4.1.0", - "@solana-program/system": "^0.5.0", + "@solana-program/system": "^0.6.1", "@solana/eslint-config-solana": "^3.0.3", - "@solana/web3.js": "2.0.0-rc.1", + "@solana/web3.js": "2.0.0-rc.4", "@types/node": "^20", "@typescript-eslint/eslint-plugin": "^7.16.1", "@typescript-eslint/parser": "^7.16.1", diff --git a/clients/js/pnpm-lock.yaml b/clients/js/pnpm-lock.yaml index 3b611f1..d4a9acc 100644 --- a/clients/js/pnpm-lock.yaml +++ b/clients/js/pnpm-lock.yaml @@ -12,14 +12,14 @@ importers: specifier: ^4.1.0 version: 4.1.0 '@solana-program/system': - specifier: ^0.5.0 - version: 0.5.1(@solana/web3.js@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)) + specifier: ^0.6.1 + version: 0.6.1(@solana/web3.js@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)) '@solana/eslint-config-solana': specifier: ^3.0.3 version: 3.0.3(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-simple-import-sort@10.0.0(eslint@8.57.0))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.2.0(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) '@solana/web3.js': - specifier: 2.0.0-rc.1 - version: 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + specifier: 2.0.0-rc.4 + version: 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) '@types/node': specifier: ^20 version: 20.14.11 @@ -360,54 +360,63 @@ packages: resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} - '@solana-program/system@0.5.1': - resolution: {integrity: sha512-2Em32hvP6Gtn9kmouAzWZiK3si5iEctvSn5MGlF8PRd6BLQ+uXtRZFOSgoMKtRSob7vtO2XpptwW2Vvmsv7jlQ==} + '@solana-program/system@0.6.1': + resolution: {integrity: sha512-vfBzveKp13gUL4M8p7wIFamPTT0aPJycUat6GcJGJRopfDX/pB8DHIURKiqFw3UGt7PJ6+koM2uWyESAifjZvA==} peerDependencies: - '@solana/web3.js': 2.0.0-rc.1 + '@solana/web3.js': 2.0.0-rc.4 - '@solana/accounts@2.0.0-rc.1': - resolution: {integrity: sha512-au6grz6iIgepKIbN2HUHKatFhg7mvIvdjFMDYpuEx+AGwK7vHnN5PsJqSCGQydthC2nVQwSZC9IgA5MF5wUHdw==} + '@solana/accounts@2.0.0-rc.4': + resolution: {integrity: sha512-LRznpCi1v/c+Gfp7/6t/kWDzTRZAPmzyr1Id3uRFsjOqGgeHYtdsK7Jw+9KMmO+PUrHqdRIFISZNMty/T17h4g==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/addresses@2.0.0-rc.1': - resolution: {integrity: sha512-g31KrLZdECjAKceShlGoYxnWDmEVklpjPs8xOtnj/HWupEk+Mds4vtmTACTAeJkWZW/3x+z0aexMtO86MKA47g==} + '@solana/addresses@2.0.0-rc.4': + resolution: {integrity: sha512-AR9g6pZMqCZeH/dShmaqyTQRCgWtZpYPQZYMazA6I5EsrKq1A40Cfxqgb/iMNl/g3vfVunT25UASH3YwBQyL/A==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/assertions@2.0.0-rc.1': - resolution: {integrity: sha512-dvxYCUB7ftZa5lWcsyMYLsGm204H6yVN8Q3ngluMG0rhTtScMBRklVg7Vs39ISwJOkJWJPGToaZ7DjNJ83bm1Q==} + '@solana/assertions@2.0.0-rc.4': + resolution: {integrity: sha512-CkTwoysagNAOjWynNzvrS5842/uDhEBjRbmgYRFurbWNLjo62j3eTYJKgTcMml7nc564Y4gObC5lUwWShGMZ/A==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-core@2.0.0-rc.1': - resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==} + '@solana/codecs-core@2.0.0-rc.4': + resolution: {integrity: sha512-JIrTSps032mSE3wBxW3bXOqWfoy4CMy1CX/XeVCijyh5kLVxZTSDIdRTYdePdL1yzaOZF1Xysvt1DhOUgBdM+A==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-data-structures@2.0.0-rc.1': - resolution: {integrity: sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog==} + '@solana/codecs-data-structures@2.0.0-rc.4': + resolution: {integrity: sha512-smF4Z4WCbr3ppoZhhT7/e5XMG6VFSHFPDLsayt4aHUvP1clZAew5uOy0qLY0qdxbttSmfoxXqf2SUFpJw8Jadg==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-numbers@2.0.0-rc.1': - resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==} + '@solana/codecs-numbers@2.0.0-rc.4': + resolution: {integrity: sha512-ZJR7TaUO65+3Hzo3YOOUCS0wlzh17IW+j0MZC2LCk1R0woaypRpHKj4iSMYeQOZkMxsd9QT3WNvjFrPC2qA6Sw==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-strings@2.0.0-rc.1': - resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==} + '@solana/codecs-strings@2.0.0-rc.4': + resolution: {integrity: sha512-LGfK2RL0BKjYYUfzu2FG/gTgCsYOMz9FKVs2ntji6WneZygPxJTV5W98K3J8Rl0JewpCSCFQH3xjLSHBJUS0fA==} + engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 typescript: '>=5' - '@solana/codecs@2.0.0-rc.1': - resolution: {integrity: sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ==} + '@solana/codecs@2.0.0-rc.4': + resolution: {integrity: sha512-h9GQGYLfBifzLhyZuef5FUaZGxLW7JNLDlEYCErA7x7Ty2ssF98sswsLsWKcbv5Cz1QsW7A6xGv4PCjvIDOCxQ==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/errors@2.0.0-rc.1': - resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==} + '@solana/errors@2.0.0-rc.4': + resolution: {integrity: sha512-0PPaMyB81keEHG/1pnyEuiBVKctbXO641M2w3CIOrYT/wzjunfF0FTxsqq9wYJeYo0AyiefCKGgSPs6wiY2PpQ==} + engines: {node: '>=20.18.0'} hasBin: true peerDependencies: typescript: '>=5' @@ -425,129 +434,160 @@ packages: eslint-plugin-typescript-sort-keys: ^3.2.0 typescript: ^5.1.6 - '@solana/fast-stable-stringify@2.0.0-rc.1': - resolution: {integrity: sha512-TN8JY+Sbh5NNq4TqdWil8hXKx2d84bTHvY6jfBXNjM29S0fwpUpVRHUzOkuK1mjjWFNkMpfgJfozC0TjdUbkvA==} + '@solana/fast-stable-stringify@2.0.0-rc.4': + resolution: {integrity: sha512-5N4S+/EGZw0Y6s2aQPNTpiB2yii2oOcrfPKXSkK4ZR2GqZuA6u6BJiJeUelXeB8P24KMxOZXfzCrkBBpEzYt6w==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/functional@2.0.0-rc.1': - resolution: {integrity: sha512-BmedS5o8HTlU8/NA22I6urJqat9QYIw0oH6rKdMMBisDwX7MtgJhe38W8iLP7QCcxoJeS4526qaD8uD62+Pheg==} + '@solana/functional@2.0.0-rc.4': + resolution: {integrity: sha512-P/rL15Svl4sREO7tqQ6V/E8zPAlIBGBnA0T75gZYGoSY5644rCiEaFoqyMkXc9l563lj1B5vV5UU8FCPkpPwmQ==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/instructions@2.0.0-rc.1': - resolution: {integrity: sha512-zkfL4WBHPbkMrYsuGZc/sekPa/oALIVvVGUw/gwAervMeLZ34cWCUE6WC2uUUh+bq3OFq0/FSFhAg2YbHHDyUw==} + '@solana/instructions@2.0.0-rc.4': + resolution: {integrity: sha512-k4KcNfrWQX5Zhij9mn6d10MnHEP4YD9qsG8SQHWTELbyoZt3UjzfzG2aY88ao3VDWz3S9JbFIzA11wjJ0TYFxg==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/keys@2.0.0-rc.1': - resolution: {integrity: sha512-ls3B0KOvfdiBH3/fnEjHhicfXsLLb4zApJlSX4X8NZ+2TmTJ2Jqa+MakgAzrsxL1FJkTJ1RDboR9xx2CHQtKzw==} + '@solana/keys@2.0.0-rc.4': + resolution: {integrity: sha512-EcepAutaXVwiW0bQZMv2gSUd+gjxL8FrqzX+BeqkfNNe1c4GxtLHOlASOXhPEH/3iGEaz6mfV6Bn5KkctWOeEA==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/options@2.0.0-rc.1': - resolution: {integrity: sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA==} + '@solana/options@2.0.0-rc.4': + resolution: {integrity: sha512-5W8aswMBhcdv2pD5lHLdHIZ98ymhQNBmeFncEoVZLTrshf7KqyxZ8xtILcWNCUgOev1+yp9hMTNV9SEgrgyNrQ==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/programs@2.0.0-rc.1': - resolution: {integrity: sha512-wF49DychwSz3sVmTF51R6DTHBGMP7Uhe7EdmCNu+Ef9EgKBJZFfrViOD6M8Q0b3WH//TV63HNlX/2QmHtJjQHg==} + '@solana/programs@2.0.0-rc.4': + resolution: {integrity: sha512-aIspYII4+EdOtK2EZaTSYNVxSzn0R1b9Lir7S+PftmzVMLOP3R5MhVb5IJcZRByJngfW227CyKQXh34fg2wWOg==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/promises@2.0.0-rc.1': - resolution: {integrity: sha512-iIaC52Ka+omGabGn2LHOSgEm9N2gI7Iyik6LE3DDxZ4MuYmGcJ4E315XuE/UVXWnc9qOfOjgtSaaOYhde0vyrQ==} + '@solana/promises@2.0.0-rc.4': + resolution: {integrity: sha512-NIY7rdtpw+le0P2vgXigJiGI54fE/bLpyiIKHfyYyjyTzCph8TmoHPX2Y/mmkmlri54tu5BM/X0UbIoXVi2dpw==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-api@2.0.0-rc.1': - resolution: {integrity: sha512-pg/w+0pgj3msBCC/hkZa9/qZHRdqh7MLsHMJInXnenO+Rzj6IyE47Ig6rt6GuI4OxYy+1d714jcPXVMA8p2YWw==} + '@solana/rpc-api@2.0.0-rc.4': + resolution: {integrity: sha512-z6KyTvVd0WkXb8WhuLAF3vLstdGl5+FVQTgxu1BbBD94bBEUC8Zg7sZuT0AS/Qdgo4Bt/oNcgXsD2DbFmb0HpQ==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-parsed-types@2.0.0-rc.1': - resolution: {integrity: sha512-5/AYNiZvR9do56VJgmTscRwnd9myt6x9uG7b0S3V+K5e0xzA9yJF68SzI4TQSNmLfWXCaVC90xGCWWkM19lLIQ==} + '@solana/rpc-parsed-types@2.0.0-rc.4': + resolution: {integrity: sha512-UvNcfi5S6WI54/t7TFi1sgdvl9wFLnk7Rmwsuq/UksAx9FuN+bdZvywkXYioh5PkcZxaDTaupnNoGRPDFxW87g==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-spec-types@2.0.0-rc.1': - resolution: {integrity: sha512-Z0gOrzasTYU+kNNnDDG2snZxBoBPMN8oFc0EE9HiDKN9JEsc+asexzKeq+Nea7JVqVFcN5V3bjqrpD86V5EOiQ==} + '@solana/rpc-spec-types@2.0.0-rc.4': + resolution: {integrity: sha512-xmyh8+xvOcm6OgxFzHNLNWs8zSjV1xOFrTtE4g44QArmzEYylzoP9bFBUEoaZvBG9ACAvT2scvwhUEREFXRAWg==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-spec@2.0.0-rc.1': - resolution: {integrity: sha512-E81IoNzLbp24T633klEqlRujd2i/rd8xVkJGt04DL/LGS4/cCWJEhkmOnfljxWafCPUundRXlPtNG3ZmHzEYqA==} + '@solana/rpc-spec@2.0.0-rc.4': + resolution: {integrity: sha512-SuME1MDYwotEDCBh0gKV50Zp2IJE/gEZc04MZBgEtEsyqB8mg9DL7PRSANJhGtx7b5gX31xw5sJmGlPHp/oUEA==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-subscriptions-api@2.0.0-rc.1': - resolution: {integrity: sha512-HmuJmB+RnpYzpiwDWncYFey0lrdFt8KbFvH0JvxEB7NX6V9NgGQIwRY1bfoaeSwX6t93p4nBWr2ckJWLNjXzCw==} + '@solana/rpc-subscriptions-api@2.0.0-rc.4': + resolution: {integrity: sha512-4TOOlYGIOqKI3vBRjQz8dZYKjExQhBUDrO1USOUm/s6GAMkNY5TVmlqvQxzo7BlsJu8f7cpK8RrQap/Ej9jHOQ==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-subscriptions-spec@2.0.0-rc.1': - resolution: {integrity: sha512-eXRVlMr9zw4JlBoJgVhFRxFs3Iaowhtt35ZIMD+OoTqgKniL62iGiZ3hXsuMDToMvQCBd0UfI+ZVdF2gLQdg9A==} + '@solana/rpc-subscriptions-channel-websocket@2.0.0-rc.4': + resolution: {integrity: sha512-Rj8vb+f5gXrJ2KBA1+gJ1eXnjawG2vNtuL/WWd/CD1xEzmBV9oFXbzcGG7tTLsQWSM9+BcgiMGhhKg5DCnpWcQ==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + ws: ^8.18.0 - '@solana/rpc-subscriptions-transport-websocket@2.0.0-rc.1': - resolution: {integrity: sha512-NxheQmG6Ku9gjF3TyGbM8Nxx6fOU3m89LdfH9SQNu6yME6VXKWuT1LaY24T707yDOoKZJsOWabRrQtNfJ+3HZA==} + '@solana/rpc-subscriptions-spec@2.0.0-rc.4': + resolution: {integrity: sha512-B0C8TYiErD34YMgdk9fmbzTti8Xo8JFYuF/2acFRD1WPLVE3UrEJSjxrmj7Lv/bO40wHvWrhUtHtzo37s9anAA==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - ws: ^8.14.0 - '@solana/rpc-subscriptions@2.0.0-rc.1': - resolution: {integrity: sha512-gHrVNWEbMi8uDO8BzpJkuDiHMcfD4SrfLRohROnHx0SfSlEGxvIkBjPnwOYIoS7IkWk95e19s7hJoBNn2TX4kw==} + '@solana/rpc-subscriptions@2.0.0-rc.4': + resolution: {integrity: sha512-9fRn2/mr6a+7hknWaqA39lSN2hO1qOIQzaOz7zql5Gj1jKM5yorgqlXBdTuCi6pRn5zni9c4yz8fU6jVJQZnGA==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-transformers@2.0.0-rc.1': - resolution: {integrity: sha512-YM25X4Eeh39UR2AoSrCFn74W99bQk0/DLqyPgZpNBRbszzEifGHqu83NNFwBuPMVc9q7ilf5s6r6pqhWP+5JJw==} + '@solana/rpc-transformers@2.0.0-rc.4': + resolution: {integrity: sha512-KpLkW6V/eAuQvZCdvCCNvcYQvq8XCxwCNmY6Y+ZJYU4EWCdMppGe4p+JJVL6buRRSGrTBW+muLhKKDsZdx/4VQ==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-transport-http@2.0.0-rc.1': - resolution: {integrity: sha512-Byvn2LnaCgTnEyr78wcgh8SrVHo+L6/l1kXQW05cNAjjbS8d8z4meBUBrXDWHmCsWy7RdnrTcBixPPtE+pUebw==} + '@solana/rpc-transport-http@2.0.0-rc.4': + resolution: {integrity: sha512-Xu6+uEPYHPF8gAJ6KsmGXqtA02Dbv9mKykf0nazt91YP66k4HYF8PaYLbGSrNR76o4TewdbqFJlipSceMJb86w==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-types@2.0.0-rc.1': - resolution: {integrity: sha512-EcGx9VXqA0+uYEdaa1lKTaGBVxLyNL8nkecE4GkqQ+ntRyYlNBPecd4b8siQGSleUQa+Tk/VSPUawSkHqNTLug==} + '@solana/rpc-types@2.0.0-rc.4': + resolution: {integrity: sha512-uSWW/VndwYF29gpvKxWo0skTxrsCKl+fYmeJz5mduIULjhr5SFdgchgb4KCcAlUMgFn4HJuwALJVHpUg0Wv10Q==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc@2.0.0-rc.1': - resolution: {integrity: sha512-upqR/Ae5syzQDZkffTdU/09k1Vx073Gt4xkkpcWaTBmW0obVhrlvJvH2k5jrOQ13BZd2NVg1MWMEOBcy3+nJjQ==} + '@solana/rpc@2.0.0-rc.4': + resolution: {integrity: sha512-YqQPf1raKUdle6iiEPQavaCdXCaX2XxHJIeZQ93lTvwuntoQUK8yAbT4go6eYQRwgL2SnR/0C4p5fnv8f/vR/A==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/signers@2.0.0-rc.1': - resolution: {integrity: sha512-dv3oKSF+AIaHKpnSkmzEf+jXVcA3nl015+Mp/WQZYzQJS01dlrmnd4N5DOSn2CaPRJ0TLujHkupxkOFXbe149A==} + '@solana/signers@2.0.0-rc.4': + resolution: {integrity: sha512-4Wm8BsXkEpiomgmsthOregxIJibL2KIzMp2NbsTQMuzB3HzRv6ATtHoiQACqnsUm0hfTV217lE/GeJdYyqHCIA==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/sysvars@2.0.0-rc.1': - resolution: {integrity: sha512-nLiuisgbRw7FkJrxPJOBzf0ro7ZCk0gWgMyLQexe9oPoTzdZnWbHI4ldYDmtfdy2dkPBsNTz6sZ6o75HwnGu0A==} + '@solana/subscribable@2.0.0-rc.4': + resolution: {integrity: sha512-ZMEL0P/kdpKeqpPI/r/zV0aCqpA2LKzd94DVOSHgDGRFWfvotRl197PInU5rcsFH1VmPsuoFH68SZYV4+2DC9Q==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/transaction-confirmation@2.0.0-rc.1': - resolution: {integrity: sha512-ES671CZUDLaXV46Vv3Kxd22coSQE4DlE7y0s9ChzQ7t4bLGv6DeHlHXU9kQBtou9koLR25wiDUWtvwNUyzUbHw==} + '@solana/sysvars@2.0.0-rc.4': + resolution: {integrity: sha512-z4XVv308IQL9RkGDPkACr2GHUrM/czzsXuv1kUscfmZmvmY77RQqaC85UYow0+opghnDpmEEssZRaWjMeVvkYw==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/transaction-messages@2.0.0-rc.1': - resolution: {integrity: sha512-pZTetOtRDwfuK/fyE8FKbtRsLQOTgEIQld3tskB85npUHaEgrnCYzp3nJtMhKOLel3w3f/27VtWLNSrRyyAiew==} + '@solana/transaction-confirmation@2.0.0-rc.4': + resolution: {integrity: sha512-ImBMZ+vkMglDECUEr8SFZw+V0Bm5TrCmNUAMqlfOgGO8v8pQUaVql0V9/KjiXu12TUYEcDZqp0PDLQ+D4I8aFg==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/transactions@2.0.0-rc.1': - resolution: {integrity: sha512-u9MH2Kk4P0E5rNxATdx/ljR2rp34S9VuC3Jzj9nCMKJ0XwvCD+ddTmIDop5Vs+96Ls9SGj0XaKAJtT+9S7SDpw==} + '@solana/transaction-messages@2.0.0-rc.4': + resolution: {integrity: sha512-zdeNIb6EtD9faVzEEfXm7Td+u5ifNCxF1/QBF6oURxaUcfX7bGXJ/P3VM0wAQ80t5zBQeqm2qzUkfEvf07NllQ==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/web3.js@2.0.0-rc.1': - resolution: {integrity: sha512-0fE40ZsJuqSOYOWbt8haHBIbhSfGckxJbwWEK+xRQaWr1sY1+MPUDnBawsLf818g9KRSNnS2Y3+/Sve7A3yfBA==} + '@solana/transactions@2.0.0-rc.4': + resolution: {integrity: sha512-n2TQ59S/SQ+LCyTgOZNXGT9gYMbMj+XeH2eMXFbg6ETs7Bhn0DE1lIfHQCq9m6JQEJ2lgH9NYFU+QDd3LGLUog==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + + '@solana/web3.js@2.0.0-rc.4': + resolution: {integrity: sha512-w1r5MjLd+6roeqMc0Dght4tLco3W9Zdoq56FnSKnbcP7Ji/L6VTdFJttf8vaIAAMDyUH5aH1yLxHrqCIW1kbrw==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' @@ -1883,8 +1923,8 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici-types@6.19.5: - resolution: {integrity: sha512-VQUzGd+K73uDi/pTqzDBbxZneciOuMRjF0r/Lep2zr/GOnU+cUvfgRu4T5k4TWJfpGdSK5nrzVDoQVoEIAFbmg==} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} unicorn-magic@0.1.0: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} @@ -2206,75 +2246,75 @@ snapshots: '@sindresorhus/merge-streams@2.3.0': {} - '@solana-program/system@0.5.1(@solana/web3.js@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0))': + '@solana-program/system@0.6.1(@solana/web3.js@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0))': dependencies: - '@solana/web3.js': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/web3.js': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) - '@solana/accounts@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/accounts@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/addresses@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/assertions': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/assertions': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/assertions@2.0.0-rc.1(typescript@5.5.3)': + '@solana/assertions@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-core@2.0.0-rc.1(typescript@5.5.3)': + '@solana/codecs-core@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-data-structures@2.0.0-rc.1(typescript@5.5.3)': + '@solana/codecs-data-structures@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-numbers@2.0.0-rc.1(typescript@5.5.3)': + '@solana/codecs-numbers@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/codecs-strings@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.5.3 - '@solana/codecs@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/codecs@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/options': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/options': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/errors@2.0.0-rc.1(typescript@5.5.3)': + '@solana/errors@2.0.0-rc.4(typescript@5.5.3)': dependencies: chalk: 5.3.0 commander: 12.1.0 @@ -2292,257 +2332,271 @@ snapshots: eslint-plugin-typescript-sort-keys: 3.2.0(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) typescript: 5.5.3 - '@solana/fast-stable-stringify@2.0.0-rc.1(typescript@5.5.3)': + '@solana/fast-stable-stringify@2.0.0-rc.4(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/functional@2.0.0-rc.1(typescript@5.5.3)': + '@solana/functional@2.0.0-rc.4(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/instructions@2.0.0-rc.1(typescript@5.5.3)': + '@solana/instructions@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - '@solana/keys@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/keys@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/assertions': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/assertions': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/options@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/programs@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/programs@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/promises@2.0.0-rc.1(typescript@5.5.3)': + '@solana/promises@2.0.0-rc.4(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/rpc-api@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': - dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-parsed-types': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-transformers': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-api@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-parsed-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-transformers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-parsed-types@2.0.0-rc.1(typescript@5.5.3)': + '@solana/rpc-parsed-types@2.0.0-rc.4(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/rpc-spec-types@2.0.0-rc.1(typescript@5.5.3)': + '@solana/rpc-spec-types@2.0.0-rc.4(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/rpc-spec@2.0.0-rc.1(typescript@5.5.3)': + '@solana/rpc-spec@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/rpc-spec-types': 2.0.0-rc.1(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - '@solana/rpc-subscriptions-api@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/rpc-subscriptions-api@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-subscriptions-spec': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-transformers': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions-spec': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-transformers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-spec@2.0.0-rc.1(typescript@5.5.3)': + '@solana/rpc-subscriptions-channel-websocket@2.0.0-rc.4(typescript@5.5.3)(ws@8.17.0)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-spec-types': 2.0.0-rc.1(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-subscriptions-spec': 2.0.0-rc.4(typescript@5.5.3) + '@solana/subscribable': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 + ws: 8.17.0 - '@solana/rpc-subscriptions-transport-websocket@2.0.0-rc.1(typescript@5.5.3)(ws@8.17.0)': + '@solana/rpc-subscriptions-spec@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-subscriptions-spec': 2.0.0-rc.1(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/promises': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/subscribable': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - ws: 8.17.0 - '@solana/rpc-subscriptions@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': - dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/fast-stable-stringify': 2.0.0-rc.1(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.1(typescript@5.5.3) - '@solana/promises': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-subscriptions-api': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-subscriptions-spec': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-subscriptions-transport-websocket': 2.0.0-rc.1(typescript@5.5.3)(ws@8.17.0) - '@solana/rpc-transformers': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/fast-stable-stringify': 2.0.0-rc.4(typescript@5.5.3) + '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) + '@solana/promises': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-subscriptions-api': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions-channel-websocket': 2.0.0-rc.4(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-subscriptions-spec': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-transformers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/subscribable': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws - '@solana/rpc-transformers@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/rpc-transformers@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-subscriptions-spec': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transport-http@2.0.0-rc.1(typescript@5.5.3)': + '@solana/rpc-transport-http@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.1(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - undici-types: 6.19.5 + undici-types: 6.20.0 - '@solana/rpc-types@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/rpc-types@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': - dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/fast-stable-stringify': 2.0.0-rc.1(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-api': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-transformers': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-transport-http': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/fast-stable-stringify': 2.0.0-rc.4(typescript@5.5.3) + '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-api': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-spec': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-transformers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-transport-http': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/signers@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/signers@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/instructions': 2.0.0-rc.1(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/instructions': 2.0.0-rc.4(typescript@5.5.3) + '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/sysvars@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/subscribable@2.0.0-rc.4(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + typescript: 5.5.3 + + '@solana/sysvars@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/accounts': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/accounts': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': - dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/promises': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-subscriptions': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-confirmation@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/promises': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws - '@solana/transaction-messages@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/transaction-messages@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.1(typescript@5.5.3) - '@solana/instructions': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) + '@solana/instructions': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transactions@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': - dependencies: - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.1(typescript@5.5.3) - '@solana/instructions': 2.0.0-rc.1(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) + '@solana/instructions': 2.0.0-rc.4(typescript@5.5.3) + '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/web3.js@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': - dependencies: - '@solana/accounts': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/addresses': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.1(typescript@5.5.3) - '@solana/instructions': 2.0.0-rc.1(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/programs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-parsed-types': 2.0.0-rc.1(typescript@5.5.3) - '@solana/rpc-subscriptions': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) - '@solana/rpc-types': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/signers': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/sysvars': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-confirmation': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) - '@solana/transaction-messages': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/web3.js@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/accounts': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) + '@solana/instructions': 2.0.0-rc.4(typescript@5.5.3) + '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/programs': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-parsed-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-subscriptions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/signers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/sysvars': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-confirmation': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -3886,7 +3940,7 @@ snapshots: undici-types@5.26.5: {} - undici-types@6.19.5: {} + undici-types@6.20.0: {} unicorn-magic@0.1.0: {} From db66175963124879d19d0109b88ad836018c130d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:24:37 +0000 Subject: [PATCH 006/335] Publish JS client v0.4.0 --- clients/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/js/package.json b/clients/js/package.json index 8ddc010..6a034c1 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,6 +1,6 @@ { "name": "@solana-program/token", - "version": "0.3.3", + "version": "0.4.0", "description": "JavaScript client for the Token program", "sideEffects": false, "module": "./dist/src/index.mjs", From 3b0829de2ec8bf18671b02917745a194e3e5be9e Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Thu, 14 Nov 2024 10:57:51 +0000 Subject: [PATCH 007/335] Bump web3.js to 2.0 (#11) Removes the RC tag. --- clients/js/package.json | 4 +- clients/js/pnpm-lock.yaml | 544 +++++++++++++++++++------------------- 2 files changed, 274 insertions(+), 274 deletions(-) diff --git a/clients/js/package.json b/clients/js/package.json index 6a034c1..2444f0a 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -42,13 +42,13 @@ }, "homepage": "https://github.com/solana-program/token#readme", "peerDependencies": { - "@solana/web3.js": "2.0.0-rc.4" + "@solana/web3.js": "^2.0.0" }, "devDependencies": { "@ava/typescript": "^4.1.0", "@solana-program/system": "^0.6.1", "@solana/eslint-config-solana": "^3.0.3", - "@solana/web3.js": "2.0.0-rc.4", + "@solana/web3.js": "^2.0.0", "@types/node": "^20", "@typescript-eslint/eslint-plugin": "^7.16.1", "@typescript-eslint/parser": "^7.16.1", diff --git a/clients/js/pnpm-lock.yaml b/clients/js/pnpm-lock.yaml index d4a9acc..3207ce9 100644 --- a/clients/js/pnpm-lock.yaml +++ b/clients/js/pnpm-lock.yaml @@ -13,13 +13,13 @@ importers: version: 4.1.0 '@solana-program/system': specifier: ^0.6.1 - version: 0.6.1(@solana/web3.js@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)) + version: 0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)) '@solana/eslint-config-solana': specifier: ^3.0.3 version: 3.0.3(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-simple-import-sort@10.0.0(eslint@8.57.0))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.2.0(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) '@solana/web3.js': - specifier: 2.0.0-rc.4 - version: 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + specifier: ^2.0.0 + version: 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) '@types/node': specifier: ^20 version: 20.14.11 @@ -365,57 +365,57 @@ packages: peerDependencies: '@solana/web3.js': 2.0.0-rc.4 - '@solana/accounts@2.0.0-rc.4': - resolution: {integrity: sha512-LRznpCi1v/c+Gfp7/6t/kWDzTRZAPmzyr1Id3uRFsjOqGgeHYtdsK7Jw+9KMmO+PUrHqdRIFISZNMty/T17h4g==} + '@solana/accounts@2.0.0': + resolution: {integrity: sha512-1CE4P3QSDH5x+ZtSthMY2mn/ekROBnlT3/4f3CHDJicDvLQsgAq2yCvGHsYkK3ZA0mxhFLuhJVjuKASPnmG1rQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/addresses@2.0.0-rc.4': - resolution: {integrity: sha512-AR9g6pZMqCZeH/dShmaqyTQRCgWtZpYPQZYMazA6I5EsrKq1A40Cfxqgb/iMNl/g3vfVunT25UASH3YwBQyL/A==} + '@solana/addresses@2.0.0': + resolution: {integrity: sha512-8n3c/mUlH1/z+pM8e7OJ6uDSXw26Be0dgYiokiqblO66DGQ0d+7pqFUFZ5pEGjJ9PU2lDTSfY8rHf4cemOqwzQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/assertions@2.0.0-rc.4': - resolution: {integrity: sha512-CkTwoysagNAOjWynNzvrS5842/uDhEBjRbmgYRFurbWNLjo62j3eTYJKgTcMml7nc564Y4gObC5lUwWShGMZ/A==} + '@solana/assertions@2.0.0': + resolution: {integrity: sha512-NyPPqZRNGXs/GAjfgsw7YS6vCTXWt4ibXveS+ciy5sdmp/0v3pA6DlzYjleF9Sljrew0IiON15rjaXamhDxYfQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-core@2.0.0-rc.4': - resolution: {integrity: sha512-JIrTSps032mSE3wBxW3bXOqWfoy4CMy1CX/XeVCijyh5kLVxZTSDIdRTYdePdL1yzaOZF1Xysvt1DhOUgBdM+A==} + '@solana/codecs-core@2.0.0': + resolution: {integrity: sha512-qCG+3hDU5Pm8V6joJjR4j4Zv9md1z0RaecniNDIkEglnxmOUODnmPLWbtOjnDylfItyuZeDihK8hkewdj8cUtw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-data-structures@2.0.0-rc.4': - resolution: {integrity: sha512-smF4Z4WCbr3ppoZhhT7/e5XMG6VFSHFPDLsayt4aHUvP1clZAew5uOy0qLY0qdxbttSmfoxXqf2SUFpJw8Jadg==} + '@solana/codecs-data-structures@2.0.0': + resolution: {integrity: sha512-N98Y4jsrC/XeOgqrfsGqcOFIaOoMsKdAxOmy5oqVaEN67YoGSLNC9ROnqamOAOrsZdicTWx9/YLKFmQi9DPh1A==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-numbers@2.0.0-rc.4': - resolution: {integrity: sha512-ZJR7TaUO65+3Hzo3YOOUCS0wlzh17IW+j0MZC2LCk1R0woaypRpHKj4iSMYeQOZkMxsd9QT3WNvjFrPC2qA6Sw==} + '@solana/codecs-numbers@2.0.0': + resolution: {integrity: sha512-r66i7VzJO1MZkQWZIAI6jjJOFVpnq0+FIabo2Z2ZDtrArFus/SbSEv543yCLeD2tdR/G/p+1+P5On10qF50Y1Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-strings@2.0.0-rc.4': - resolution: {integrity: sha512-LGfK2RL0BKjYYUfzu2FG/gTgCsYOMz9FKVs2ntji6WneZygPxJTV5W98K3J8Rl0JewpCSCFQH3xjLSHBJUS0fA==} + '@solana/codecs-strings@2.0.0': + resolution: {integrity: sha512-dNqeCypsvaHcjW86H0gYgAZGGkKVBeKVeh7WXlOZ9kno7PeQ2wNkpccyzDfuzaIsKv+HZUD3v/eo86GCvnKazQ==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 typescript: '>=5' - '@solana/codecs@2.0.0-rc.4': - resolution: {integrity: sha512-h9GQGYLfBifzLhyZuef5FUaZGxLW7JNLDlEYCErA7x7Ty2ssF98sswsLsWKcbv5Cz1QsW7A6xGv4PCjvIDOCxQ==} + '@solana/codecs@2.0.0': + resolution: {integrity: sha512-xneIG5ppE6WIGaZCK7JTys0uLhzlnEJUdBO8nRVIyerwH6aqCfb0fGe7q5WNNYAVDRSxC0Pc1TDe1hpdx3KWmQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/errors@2.0.0-rc.4': - resolution: {integrity: sha512-0PPaMyB81keEHG/1pnyEuiBVKctbXO641M2w3CIOrYT/wzjunfF0FTxsqq9wYJeYo0AyiefCKGgSPs6wiY2PpQ==} + '@solana/errors@2.0.0': + resolution: {integrity: sha512-IHlaPFSy4lvYco1oHJ3X8DbchWwAwJaL/4wZKnF1ugwZ0g0re8wbABrqNOe/jyZ84VU9Z14PYM8W9oDAebdJbw==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: @@ -434,159 +434,159 @@ packages: eslint-plugin-typescript-sort-keys: ^3.2.0 typescript: ^5.1.6 - '@solana/fast-stable-stringify@2.0.0-rc.4': - resolution: {integrity: sha512-5N4S+/EGZw0Y6s2aQPNTpiB2yii2oOcrfPKXSkK4ZR2GqZuA6u6BJiJeUelXeB8P24KMxOZXfzCrkBBpEzYt6w==} + '@solana/fast-stable-stringify@2.0.0': + resolution: {integrity: sha512-EsIx9z+eoxOmC+FpzhEb+H67CCYTbs/omAqXD4EdEYnCHWrI1li1oYBV+NoKzfx8fKlX+nzNB7S/9kc4u7Etpw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/functional@2.0.0-rc.4': - resolution: {integrity: sha512-P/rL15Svl4sREO7tqQ6V/E8zPAlIBGBnA0T75gZYGoSY5644rCiEaFoqyMkXc9l563lj1B5vV5UU8FCPkpPwmQ==} + '@solana/functional@2.0.0': + resolution: {integrity: sha512-Sj+sLiUTimnMEyGnSLGt0lbih2xPDUhxhonnrIkPwA+hjQ3ULGHAxeevHU06nqiVEgENQYUJ5rCtHs4xhUFAkQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/instructions@2.0.0-rc.4': - resolution: {integrity: sha512-k4KcNfrWQX5Zhij9mn6d10MnHEP4YD9qsG8SQHWTELbyoZt3UjzfzG2aY88ao3VDWz3S9JbFIzA11wjJ0TYFxg==} + '@solana/instructions@2.0.0': + resolution: {integrity: sha512-MiTEiNF7Pzp+Y+x4yadl2VUcNHboaW5WP52psBuhHns3GpbbruRv5efMpM9OEQNe1OsN+Eg39vjEidX55+P+DQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/keys@2.0.0-rc.4': - resolution: {integrity: sha512-EcepAutaXVwiW0bQZMv2gSUd+gjxL8FrqzX+BeqkfNNe1c4GxtLHOlASOXhPEH/3iGEaz6mfV6Bn5KkctWOeEA==} + '@solana/keys@2.0.0': + resolution: {integrity: sha512-SSLSX8BXRvfLKBqsmBghmlhMKpwHeWd5CHi5zXgTS1BRrtiU6lcrTVC9ie6B+WaNNq7oe3e6K5bdbhu3fFZ+0g==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/options@2.0.0-rc.4': - resolution: {integrity: sha512-5W8aswMBhcdv2pD5lHLdHIZ98ymhQNBmeFncEoVZLTrshf7KqyxZ8xtILcWNCUgOev1+yp9hMTNV9SEgrgyNrQ==} + '@solana/options@2.0.0': + resolution: {integrity: sha512-OVc4KnYosB8oAukQ/htgrxXSxlUP6gUu5Aau6d/BgEkPQzWd/Pr+w91VWw3i3zZuu2SGpedbyh05RoJBe/hSXA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/programs@2.0.0-rc.4': - resolution: {integrity: sha512-aIspYII4+EdOtK2EZaTSYNVxSzn0R1b9Lir7S+PftmzVMLOP3R5MhVb5IJcZRByJngfW227CyKQXh34fg2wWOg==} + '@solana/programs@2.0.0': + resolution: {integrity: sha512-JPIKB61pWfODnsvEAaPALc6vR5rn7kmHLpFaviWhBtfUlEVgB8yVTR0MURe4+z+fJCPRV5wWss+svA4EeGDYzQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/promises@2.0.0-rc.4': - resolution: {integrity: sha512-NIY7rdtpw+le0P2vgXigJiGI54fE/bLpyiIKHfyYyjyTzCph8TmoHPX2Y/mmkmlri54tu5BM/X0UbIoXVi2dpw==} + '@solana/promises@2.0.0': + resolution: {integrity: sha512-4teQ52HDjK16ORrZe1zl+Q9WcZdQ+YEl0M1gk59XG7D0P9WqaVEQzeXGnKSCs+Y9bnB1u5xCJccwpUhHYWq6gg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-api@2.0.0-rc.4': - resolution: {integrity: sha512-z6KyTvVd0WkXb8WhuLAF3vLstdGl5+FVQTgxu1BbBD94bBEUC8Zg7sZuT0AS/Qdgo4Bt/oNcgXsD2DbFmb0HpQ==} + '@solana/rpc-api@2.0.0': + resolution: {integrity: sha512-1FwitYxwADMF/6zKP2kNXg8ESxB6GhNBNW1c4f5dEmuXuBbeD/enLV3WMrpg8zJkIaaYarEFNbt7R7HyFzmURQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-parsed-types@2.0.0-rc.4': - resolution: {integrity: sha512-UvNcfi5S6WI54/t7TFi1sgdvl9wFLnk7Rmwsuq/UksAx9FuN+bdZvywkXYioh5PkcZxaDTaupnNoGRPDFxW87g==} + '@solana/rpc-parsed-types@2.0.0': + resolution: {integrity: sha512-VCeY/oKVEtBnp8EDOc5LSSiOeIOLFIgLndcxqU0ij/cZaQ01DOoHbhluvhZtU80Z3dUeicec8TiMgkFzed+WhQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-spec-types@2.0.0-rc.4': - resolution: {integrity: sha512-xmyh8+xvOcm6OgxFzHNLNWs8zSjV1xOFrTtE4g44QArmzEYylzoP9bFBUEoaZvBG9ACAvT2scvwhUEREFXRAWg==} + '@solana/rpc-spec-types@2.0.0': + resolution: {integrity: sha512-G2lmhFhgtxMQd/D6B04BHGE7bm5dMZdIPQNOqVGhzNAVjrmyapD3JN2hKAbmaYPe97wLfZERw0Ux1u4Y6q7TqA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-spec@2.0.0-rc.4': - resolution: {integrity: sha512-SuME1MDYwotEDCBh0gKV50Zp2IJE/gEZc04MZBgEtEsyqB8mg9DL7PRSANJhGtx7b5gX31xw5sJmGlPHp/oUEA==} + '@solana/rpc-spec@2.0.0': + resolution: {integrity: sha512-1uIDzj7vocCUqfOifjv1zAuxQ53ugiup/42edVFoQLOnJresoEZLL6WjnsJq4oCTccEAvGhUBI1WWKeZTGNxFQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-subscriptions-api@2.0.0-rc.4': - resolution: {integrity: sha512-4TOOlYGIOqKI3vBRjQz8dZYKjExQhBUDrO1USOUm/s6GAMkNY5TVmlqvQxzo7BlsJu8f7cpK8RrQap/Ej9jHOQ==} + '@solana/rpc-subscriptions-api@2.0.0': + resolution: {integrity: sha512-NAJQvSFXYIIf8zxsMFBCkSbZNZgT32pzPZ1V6ZAd+U2iDEjx3L+yFwoJgfOcHp8kAV+alsF2lIsGBlG4u+ehvw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-subscriptions-channel-websocket@2.0.0-rc.4': - resolution: {integrity: sha512-Rj8vb+f5gXrJ2KBA1+gJ1eXnjawG2vNtuL/WWd/CD1xEzmBV9oFXbzcGG7tTLsQWSM9+BcgiMGhhKg5DCnpWcQ==} + '@solana/rpc-subscriptions-channel-websocket@2.0.0': + resolution: {integrity: sha512-hSQDZBmcp2t+gLZsSBqs/SqVw4RuNSC7njiP46azyzW7oGg8X2YPV36AHGsHD12KPsc0UpT1OAZ4+AN9meVKww==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' ws: ^8.18.0 - '@solana/rpc-subscriptions-spec@2.0.0-rc.4': - resolution: {integrity: sha512-B0C8TYiErD34YMgdk9fmbzTti8Xo8JFYuF/2acFRD1WPLVE3UrEJSjxrmj7Lv/bO40wHvWrhUtHtzo37s9anAA==} + '@solana/rpc-subscriptions-spec@2.0.0': + resolution: {integrity: sha512-VXMiI3fYtU1PkVVTXL87pcY48ZY8aCi1N6FqtxSP2xg/GASL01j1qbwyIL1OvoCqGyRgIxdd/YfaByW9wmWBhA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-subscriptions@2.0.0-rc.4': - resolution: {integrity: sha512-9fRn2/mr6a+7hknWaqA39lSN2hO1qOIQzaOz7zql5Gj1jKM5yorgqlXBdTuCi6pRn5zni9c4yz8fU6jVJQZnGA==} + '@solana/rpc-subscriptions@2.0.0': + resolution: {integrity: sha512-AdwMJHMrhlj7q1MPjZmVcKq3iLqMW3N0MT8kzIAP2vP+8o/d6Fn4aqGxoz2Hlfn3OYIZoYStN2VBtwzbcfEgMA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-transformers@2.0.0-rc.4': - resolution: {integrity: sha512-KpLkW6V/eAuQvZCdvCCNvcYQvq8XCxwCNmY6Y+ZJYU4EWCdMppGe4p+JJVL6buRRSGrTBW+muLhKKDsZdx/4VQ==} + '@solana/rpc-transformers@2.0.0': + resolution: {integrity: sha512-H6tN0qcqzUangowsLLQtYXKJsf1Roe3/qJ1Cy0gv9ojY9uEvNbJqpeEj+7blv0MUZfEe+rECAwBhxxRKPMhYGw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-transport-http@2.0.0-rc.4': - resolution: {integrity: sha512-Xu6+uEPYHPF8gAJ6KsmGXqtA02Dbv9mKykf0nazt91YP66k4HYF8PaYLbGSrNR76o4TewdbqFJlipSceMJb86w==} + '@solana/rpc-transport-http@2.0.0': + resolution: {integrity: sha512-UJLhKhhxDd1OPi8hb2AenHsDm1mofCBbhWn4bDCnH2Q3ulwYadUhcNqNbxjJPQ774VNhAf53SSI5A6PQo8IZSQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc-types@2.0.0-rc.4': - resolution: {integrity: sha512-uSWW/VndwYF29gpvKxWo0skTxrsCKl+fYmeJz5mduIULjhr5SFdgchgb4KCcAlUMgFn4HJuwALJVHpUg0Wv10Q==} + '@solana/rpc-types@2.0.0': + resolution: {integrity: sha512-o1ApB9PYR0A3XjVSOh//SOVWgjDcqMlR3UNmtqciuREIBmWqnvPirdOa5EJxD3iPhfA4gnNnhGzT+tMDeDW/Kw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/rpc@2.0.0-rc.4': - resolution: {integrity: sha512-YqQPf1raKUdle6iiEPQavaCdXCaX2XxHJIeZQ93lTvwuntoQUK8yAbT4go6eYQRwgL2SnR/0C4p5fnv8f/vR/A==} + '@solana/rpc@2.0.0': + resolution: {integrity: sha512-TumQ9DFRpib/RyaIqLVfr7UjqSo7ldfzpae0tgjM93YjbItB4Z0VcUXc3uAFvkeYw2/HIMb46Zg43mkUwozjDg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/signers@2.0.0-rc.4': - resolution: {integrity: sha512-4Wm8BsXkEpiomgmsthOregxIJibL2KIzMp2NbsTQMuzB3HzRv6ATtHoiQACqnsUm0hfTV217lE/GeJdYyqHCIA==} + '@solana/signers@2.0.0': + resolution: {integrity: sha512-JEYJS3x/iKkqPV/3b1nLpX9lHib21wQKV3fOuu1aDLQqmX9OYKrnIIITYdnFDhmvGhpEpkkbPnqu7yVaFIBYsQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/subscribable@2.0.0-rc.4': - resolution: {integrity: sha512-ZMEL0P/kdpKeqpPI/r/zV0aCqpA2LKzd94DVOSHgDGRFWfvotRl197PInU5rcsFH1VmPsuoFH68SZYV4+2DC9Q==} + '@solana/subscribable@2.0.0': + resolution: {integrity: sha512-Ex7d2GnTSNVMZDU3z6nKN4agRDDgCgBDiLnmn1hmt0iFo3alr3gRAqiqa7qGouAtYh9/29pyc8tVJCijHWJPQQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/sysvars@2.0.0-rc.4': - resolution: {integrity: sha512-z4XVv308IQL9RkGDPkACr2GHUrM/czzsXuv1kUscfmZmvmY77RQqaC85UYow0+opghnDpmEEssZRaWjMeVvkYw==} + '@solana/sysvars@2.0.0': + resolution: {integrity: sha512-8D4ajKcCYQsTG1p4k30lre2vjxLR6S5MftUGJnIaQObDCzGmaeA9GRti4Kk4gSPWVYFTBoj1ASx8EcEXaB3eIQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/transaction-confirmation@2.0.0-rc.4': - resolution: {integrity: sha512-ImBMZ+vkMglDECUEr8SFZw+V0Bm5TrCmNUAMqlfOgGO8v8pQUaVql0V9/KjiXu12TUYEcDZqp0PDLQ+D4I8aFg==} + '@solana/transaction-confirmation@2.0.0': + resolution: {integrity: sha512-JkTw5gXLiqQjf6xK0fpVcoJ/aMp2kagtFSD/BAOazdJ3UYzOzbzqvECt6uWa3ConcMswQ2vXalVtI7ZjmYuIeg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/transaction-messages@2.0.0-rc.4': - resolution: {integrity: sha512-zdeNIb6EtD9faVzEEfXm7Td+u5ifNCxF1/QBF6oURxaUcfX7bGXJ/P3VM0wAQ80t5zBQeqm2qzUkfEvf07NllQ==} + '@solana/transaction-messages@2.0.0': + resolution: {integrity: sha512-Uc6Fw1EJLBrmgS1lH2ZfLAAKFvprWPQQzOVwZS78Pv8Whsk7tweYTK6S0Upv0nHr50rGpnORJfmdBrXE6OfNGg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/transactions@2.0.0-rc.4': - resolution: {integrity: sha512-n2TQ59S/SQ+LCyTgOZNXGT9gYMbMj+XeH2eMXFbg6ETs7Bhn0DE1lIfHQCq9m6JQEJ2lgH9NYFU+QDd3LGLUog==} + '@solana/transactions@2.0.0': + resolution: {integrity: sha512-VfdTE+59WKvuBG//6iE9RPjAB+ZT2kLgY2CDHabaz6RkH6OjOkMez9fWPVa3Xtcus+YQWN1SnQoryjF/xSx04w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/web3.js@2.0.0-rc.4': - resolution: {integrity: sha512-w1r5MjLd+6roeqMc0Dght4tLco3W9Zdoq56FnSKnbcP7Ji/L6VTdFJttf8vaIAAMDyUH5aH1yLxHrqCIW1kbrw==} + '@solana/web3.js@2.0.0': + resolution: {integrity: sha512-x+ZRB2/r5tVK/xw8QRbAfgPcX51G9f2ifEyAQ/J5npOO+6+MPeeCjtr5UxHNDAYs9Ypo0PN+YJATCO4vhzQJGg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' @@ -2246,75 +2246,75 @@ snapshots: '@sindresorhus/merge-streams@2.3.0': {} - '@solana-program/system@0.6.1(@solana/web3.js@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0))': + '@solana-program/system@0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0))': dependencies: - '@solana/web3.js': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) - '@solana/accounts@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/accounts@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec': 2.0.0(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/addresses@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/assertions': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/assertions': 2.0.0(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/assertions@2.0.0-rc.4(typescript@5.5.3)': + '@solana/assertions@2.0.0(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-core@2.0.0-rc.4(typescript@5.5.3)': + '@solana/codecs-core@2.0.0(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-data-structures@2.0.0-rc.4(typescript@5.5.3)': + '@solana/codecs-data-structures@2.0.0(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-numbers@2.0.0-rc.4(typescript@5.5.3)': + '@solana/codecs-numbers@2.0.0(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-strings@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/codecs-strings@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.5.3 - '@solana/codecs@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/codecs@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-data-structures': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/options': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/options': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/errors@2.0.0-rc.4(typescript@5.5.3)': + '@solana/errors@2.0.0(typescript@5.5.3)': dependencies: chalk: 5.3.0 commander: 12.1.0 @@ -2332,271 +2332,271 @@ snapshots: eslint-plugin-typescript-sort-keys: 3.2.0(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) typescript: 5.5.3 - '@solana/fast-stable-stringify@2.0.0-rc.4(typescript@5.5.3)': + '@solana/fast-stable-stringify@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/functional@2.0.0-rc.4(typescript@5.5.3)': + '@solana/functional@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/instructions@2.0.0-rc.4(typescript@5.5.3)': + '@solana/instructions@2.0.0(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/keys@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/keys@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/assertions': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/assertions': 2.0.0(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/options@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-data-structures': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/programs@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/programs@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/promises@2.0.0-rc.4(typescript@5.5.3)': + '@solana/promises@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/rpc-api@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': - dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-parsed-types': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-transformers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-api@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-parsed-types': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec': 2.0.0(typescript@5.5.3) + '@solana/rpc-transformers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-parsed-types@2.0.0-rc.4(typescript@5.5.3)': + '@solana/rpc-parsed-types@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/rpc-spec-types@2.0.0-rc.4(typescript@5.5.3)': + '@solana/rpc-spec-types@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 - '@solana/rpc-spec@2.0.0-rc.4(typescript@5.5.3)': + '@solana/rpc-spec@2.0.0(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/rpc-subscriptions-api@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/rpc-subscriptions-api@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-subscriptions-spec': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-transformers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions-spec': 2.0.0(typescript@5.5.3) + '@solana/rpc-transformers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@2.0.0-rc.4(typescript@5.5.3)(ws@8.17.0)': + '@solana/rpc-subscriptions-channel-websocket@2.0.0(typescript@5.5.3)(ws@8.17.0)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-subscriptions-spec': 2.0.0-rc.4(typescript@5.5.3) - '@solana/subscribable': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/functional': 2.0.0(typescript@5.5.3) + '@solana/rpc-subscriptions-spec': 2.0.0(typescript@5.5.3) + '@solana/subscribable': 2.0.0(typescript@5.5.3) typescript: 5.5.3 ws: 8.17.0 - '@solana/rpc-subscriptions-spec@2.0.0-rc.4(typescript@5.5.3)': + '@solana/rpc-subscriptions-spec@2.0.0(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/promises': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) - '@solana/subscribable': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/promises': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0(typescript@5.5.3) + '@solana/subscribable': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/rpc-subscriptions@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': - dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/fast-stable-stringify': 2.0.0-rc.4(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) - '@solana/promises': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-subscriptions-api': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-subscriptions-channel-websocket': 2.0.0-rc.4(typescript@5.5.3)(ws@8.17.0) - '@solana/rpc-subscriptions-spec': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-transformers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/subscribable': 2.0.0-rc.4(typescript@5.5.3) + '@solana/rpc-subscriptions@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/fast-stable-stringify': 2.0.0(typescript@5.5.3) + '@solana/functional': 2.0.0(typescript@5.5.3) + '@solana/promises': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0(typescript@5.5.3) + '@solana/rpc-subscriptions-api': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions-channel-websocket': 2.0.0(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-subscriptions-spec': 2.0.0(typescript@5.5.3) + '@solana/rpc-transformers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/subscribable': 2.0.0(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws - '@solana/rpc-transformers@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/rpc-transformers@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/functional': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transport-http@2.0.0-rc.4(typescript@5.5.3)': + '@solana/rpc-transport-http@2.0.0(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0(typescript@5.5.3) typescript: 5.5.3 undici-types: 6.20.0 - '@solana/rpc-types@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/rpc-types@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': - dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/fast-stable-stringify': 2.0.0-rc.4(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-api': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-spec': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-transformers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-transport-http': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/fast-stable-stringify': 2.0.0(typescript@5.5.3) + '@solana/functional': 2.0.0(typescript@5.5.3) + '@solana/rpc-api': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-spec': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0(typescript@5.5.3) + '@solana/rpc-transformers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-transport-http': 2.0.0(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/signers@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/signers@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/instructions': 2.0.0-rc.4(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/instructions': 2.0.0(typescript@5.5.3) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/subscribable@2.0.0-rc.4(typescript@5.5.3)': + '@solana/subscribable@2.0.0(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/sysvars@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/sysvars@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/accounts': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/accounts': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': - dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/promises': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-subscriptions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-confirmation@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/promises': 2.0.0(typescript@5.5.3) + '@solana/rpc': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws - '@solana/transaction-messages@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/transaction-messages@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-data-structures': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) - '@solana/instructions': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/functional': 2.0.0(typescript@5.5.3) + '@solana/instructions': 2.0.0(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transactions@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': - dependencies: - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-data-structures': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) - '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) - '@solana/instructions': 2.0.0-rc.4(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/functional': 2.0.0(typescript@5.5.3) + '@solana/instructions': 2.0.0(typescript@5.5.3) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/web3.js@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': - dependencies: - '@solana/accounts': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/addresses': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/codecs': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) - '@solana/functional': 2.0.0-rc.4(typescript@5.5.3) - '@solana/instructions': 2.0.0-rc.4(typescript@5.5.3) - '@solana/keys': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/programs': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/rpc-parsed-types': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-spec-types': 2.0.0-rc.4(typescript@5.5.3) - '@solana/rpc-subscriptions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) - '@solana/rpc-types': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/signers': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/sysvars': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transaction-confirmation': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) - '@solana/transaction-messages': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) - '@solana/transactions': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/accounts': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + '@solana/functional': 2.0.0(typescript@5.5.3) + '@solana/instructions': 2.0.0(typescript@5.5.3) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/programs': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-parsed-types': 2.0.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.0.0(typescript@5.5.3) + '@solana/rpc-subscriptions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/signers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/sysvars': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-confirmation': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder From e433d74c18c5c9184e7e09259bce9b1aa593695d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:04:04 +0000 Subject: [PATCH 008/335] Publish JS client v0.4.1 --- clients/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/js/package.json b/clients/js/package.json index 2444f0a..1339b8a 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,6 +1,6 @@ { "name": "@solana-program/token", - "version": "0.4.0", + "version": "0.4.1", "description": "JavaScript client for the Token program", "sideEffects": false, "module": "./dist/src/index.mjs", From 01873468e2d195db43967a37a77ceae8a945e49a Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 7 Aug 2020 23:58:18 -0700 Subject: [PATCH 009/335] Reorganize crates based on program --- program/Cargo.toml | 35 + program/README.md | 10 + program/Xargo.toml | 2 + program/build.rs | 65 + program/inc/token.h | 359 + program/js/.eslintignore | 1 + program/js/.eslintrc.js | 56 + program/js/.flowconfig | 20 + program/js/.gitignore | 1 + program/js/.prettierrc.yaml | 7 + program/js/README.md | 69 + program/js/babel.config.json | 17 + program/js/babel.rollup.config.json | 18 + program/js/cli/main.js | 58 + program/js/cli/token-test.js | 500 + program/js/client/layout.js | 47 + program/js/client/token.js | 1242 +++ .../client/util/new-account-with-lamports.js | 25 + .../util/new-system-account-with-airdrop.js | 17 + .../util/send-and-confirm-transaction.js | 21 + program/js/client/util/sleep.js | 6 + program/js/client/util/store.js | 26 + program/js/cluster-devnet.env | 2 + program/js/cluster-mainnet-beta.env | 2 + program/js/cluster-testnet.env | 2 + program/js/flow-typed/bn.js.js | 4 + program/js/flow-typed/bs58.js | 6 + program/js/flow-typed/buffer-layout.js | 4 + .../js/flow-typed/mkdirp-promise_vx.x.x.js | 32 + program/js/flow-typed/npm/mz_vx.x.x.js | 73 + program/js/flow-typed/semver.js | 3 + program/js/module.d.ts | 160 + program/js/module.flow.js | 163 + program/js/package-lock.json | 8383 +++++++++++++++++ program/js/package.json | 78 + program/js/rollup.config.js | 74 + program/js/url.js | 31 + program/program-id.md | 1 + program/src/entrypoint.rs | 24 + program/src/error.rs | 56 + program/src/instruction.rs | 593 ++ program/src/lib.rs | 28 + program/src/native_mint.rs | 25 + program/src/option.rs | 965 ++ program/src/processor.rs | 2232 +++++ program/src/state.rs | 92 + 46 files changed, 15635 insertions(+) create mode 100644 program/Cargo.toml create mode 100644 program/README.md create mode 100644 program/Xargo.toml create mode 100644 program/build.rs create mode 100644 program/inc/token.h create mode 100644 program/js/.eslintignore create mode 100644 program/js/.eslintrc.js create mode 100644 program/js/.flowconfig create mode 100644 program/js/.gitignore create mode 100644 program/js/.prettierrc.yaml create mode 100644 program/js/README.md create mode 100644 program/js/babel.config.json create mode 100644 program/js/babel.rollup.config.json create mode 100644 program/js/cli/main.js create mode 100644 program/js/cli/token-test.js create mode 100644 program/js/client/layout.js create mode 100644 program/js/client/token.js create mode 100644 program/js/client/util/new-account-with-lamports.js create mode 100644 program/js/client/util/new-system-account-with-airdrop.js create mode 100644 program/js/client/util/send-and-confirm-transaction.js create mode 100644 program/js/client/util/sleep.js create mode 100644 program/js/client/util/store.js create mode 100644 program/js/cluster-devnet.env create mode 100644 program/js/cluster-mainnet-beta.env create mode 100644 program/js/cluster-testnet.env create mode 100644 program/js/flow-typed/bn.js.js create mode 100644 program/js/flow-typed/bs58.js create mode 100644 program/js/flow-typed/buffer-layout.js create mode 100644 program/js/flow-typed/mkdirp-promise_vx.x.x.js create mode 100644 program/js/flow-typed/npm/mz_vx.x.x.js create mode 100644 program/js/flow-typed/semver.js create mode 100644 program/js/module.d.ts create mode 100644 program/js/module.flow.js create mode 100644 program/js/package-lock.json create mode 100644 program/js/package.json create mode 100644 program/js/rollup.config.js create mode 100644 program/js/url.js create mode 100644 program/program-id.md create mode 100644 program/src/entrypoint.rs create mode 100644 program/src/error.rs create mode 100644 program/src/instruction.rs create mode 100644 program/src/lib.rs create mode 100644 program/src/native_mint.rs create mode 100644 program/src/option.rs create mode 100644 program/src/processor.rs create mode 100644 program/src/state.rs diff --git a/program/Cargo.toml b/program/Cargo.toml new file mode 100644 index 0000000..f370b73 --- /dev/null +++ b/program/Cargo.toml @@ -0,0 +1,35 @@ + +# Note: This crate must be built using do.sh + +[package] +name = "spl-token" +version = "1.0.6" +description = "Solana Program Library Token" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2018" +exclude = ["js/**"] + +[features] +no-entrypoint = [] +skip-no-mangle = ["solana-sdk/skip-no-mangle"] +program = ["solana-sdk/program"] +default = ["solana-sdk/default"] + +[dependencies] +num-derive = "0.3" +num-traits = "0.2" +remove_dir_all = "=0.5.0" +solana-sdk = { version = "1.2.17", default-features = false, optional = true } +thiserror = "1.0" + +[dev-dependencies] +rand = { version = "0.7.0"} + +[build-dependencies] +cbindgen = "=0.14.2" + +[lib] +name = "spl_token" +crate-type = ["cdylib", "lib"] diff --git a/program/README.md b/program/README.md new file mode 100644 index 0000000..53b4e01 --- /dev/null +++ b/program/README.md @@ -0,0 +1,10 @@ +# Token program + +A Fungible Token program on the Solana blockchain. + +This program provides an interface and implementation that third parties can +utilize to create and use their tokens. + +Full documentation is available at https://spl.solana.com + +Javascript binding are available in the `./js` directory. diff --git a/program/Xargo.toml b/program/Xargo.toml new file mode 100644 index 0000000..1744f09 --- /dev/null +++ b/program/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] \ No newline at end of file diff --git a/program/build.rs b/program/build.rs new file mode 100644 index 0000000..161616c --- /dev/null +++ b/program/build.rs @@ -0,0 +1,65 @@ +extern crate cbindgen; + +use std::env; + +fn main() { + println!("cargo:rerun-if-env-changed=SPL_CBINDGEN"); + println!("cargo:rerun-if-changed=inc/token.h"); + if std::path::Path::new("inc/token.h").exists() && env::var("SPL_CBINDGEN").is_err() { + return; + } + + println!("cargo:warning=Generating inc/token.h"); + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let config = cbindgen::Config { + header: Some("/* Autogenerated SPL Token program C Bindings */".to_string()), + after_includes: Some(format!( + "{}{}{}", + format!( + "\n#define TOKEN_MAJOR_VERSION {}", + env!("CARGO_PKG_VERSION_MAJOR") + ), + format!( + "\n#define TOKEN_MINOR_VERSION {}", + env!("CARGO_PKG_VERSION_MINOR") + ), + format!( + "\n#define TOKEN_PATCH_VERSION {}", + env!("CARGO_PKG_VERSION_PATCH") + ) + )), + language: cbindgen::Language::C, + line_length: 80, + style: cbindgen::Style::Both, + tab_width: 4, + cpp_compat: true, + pragma_once: true, + enumeration: cbindgen::EnumConfig { + prefix_with_name: true, + ..cbindgen::EnumConfig::default() + }, + export: cbindgen::ExportConfig { + prefix: Some("Token_".to_string()), + include: vec![ + "TokenInstruction".to_string(), + "TokenInstruction".to_string(), + "Mint".to_string(), + "Account".to_string(), + "Multisig".to_string(), + ], + ..cbindgen::ExportConfig::default() + }, + parse: cbindgen::ParseConfig { + parse_deps: true, + include: Some(vec!["solana-sdk".to_string()]), + ..cbindgen::ParseConfig::default() + }, + ..cbindgen::Config::default() + }; + cbindgen::Builder::new() + .with_crate(crate_dir) + .with_config(config) + .generate() + .unwrap() + .write_to_file("inc/token.h"); +} diff --git a/program/inc/token.h b/program/inc/token.h new file mode 100644 index 0000000..2efb6c3 --- /dev/null +++ b/program/inc/token.h @@ -0,0 +1,359 @@ +/* Autogenerated SPL Token program C Bindings */ + +#pragma once + +#include +#include +#include +#include + +#define TOKEN_MAJOR_VERSION 1 +#define TOKEN_MINOR_VERSION 0 +#define TOKEN_PATCH_VERSION 6 + +/** + * Maximum number of multisignature signers (max N) + */ +#define Token_MAX_SIGNERS 11 + +/** + * Minimum number of multisignature signers (min N) + */ +#define Token_MIN_SIGNERS 1 + +/** + * Instructions supported by the token program. + */ +typedef enum Token_TokenInstruction_Tag { + /** + * Initializes a new mint and optionally deposits all the newly minted tokens in an account. + * + * The `InitializeMint` instruction requires no signers and MUST be included within + * the same Transaction as the system program's `CreateInstruction` that creates the account + * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * + * Accounts expected by this instruction: + * + * 0. `[writable]` The mint to initialize. + * 1. + * * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. + * * If supply is zero: `[]` The owner/multisignature of the mint. + * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if + * present then further minting is supported. + * + */ + Token_TokenInstruction_InitializeMint, + /** + * Initializes a new account to hold tokens. If this account is associated with the native mint + * then the token balance of the initialized account will be equal to the amount of SOL in the account. + * + * The `InitializeAccount` instruction requires no signers and MUST be included within + * the same Transaction as the system program's `CreateInstruction` that creates the account + * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * + * Accounts expected by this instruction: + * + * 0. `[writable]` The account to initialize. + * 1. `[]` The mint this account will be associated with. + * 2. `[]` The new account's owner/multisignature. + */ + Token_TokenInstruction_InitializeAccount, + /** + * Initializes a multisignature account with N provided signers. + * + * Multisignature accounts can used in place of any single owner/delegate accounts in any + * token instruction that require an owner/delegate to be present. The variant field represents the + * number of signers (M) required to validate this multisignature account. + * + * The `InitializeMultisig` instruction requires no signers and MUST be included within + * the same Transaction as the system program's `CreateInstruction` that creates the account + * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * + * Accounts expected by this instruction: + * + * 0. `[writable]` The multisignature account to initialize. + * 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + */ + Token_TokenInstruction_InitializeMultisig, + /** + * Transfers tokens from one account to another either directly or via a delegate. If this + * account is associated with the native mint then equal amounts of SOL and Tokens will be + * transferred to the destination account. + * + * Accounts expected by this instruction: + * + * * Single owner/delegate + * 0. `[writable]` The source account. + * 1. `[writable]` The destination account. + * 2. '[signer]' The source account's owner/delegate. + * + * * Multisignature owner/delegate + * 0. `[writable]` The source account. + * 1. `[writable]` The destination account. + * 2. '[]' The source account's multisignature owner/delegate. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_Transfer, + /** + * Approves a delegate. A delegate is given the authority over + * tokens on behalf of the source account's owner. + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The source account. + * 1. `[]` The delegate. + * 2. `[signer]` The source account owner. + * + * * Multisignature owner + * 0. `[writable]` The source account. + * 1. `[]` The delegate. + * 2. '[]' The source account's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts + */ + Token_TokenInstruction_Approve, + /** + * Revokes the delegate's authority. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The source account. + * 1. `[signer]` The source account owner. + * + * * Multisignature owner + * 0. `[writable]` The source account. + * 1. '[]' The source account's multisignature owner. + * 2. ..2+M '[signer]' M signer accounts + */ + Token_TokenInstruction_Revoke, + /** + * Sets a new owner of a mint or account. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The mint or account to change the owner of. + * 1. `[]` The new owner/delegate/multisignature. + * 2. `[signer]` The owner of the mint or account. + * + * * Multisignature owner + * 0. `[writable]` The mint or account to change the owner of. + * 1. `[]` The new owner/delegate/multisignature. + * 2. `[]` The mint's or account's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts + */ + Token_TokenInstruction_SetOwner, + /** + * Mints new tokens to an account. The native mint does not support minting. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The mint. + * 1. `[writable]` The account to mint tokens to. + * 2. `[signer]` The mint's owner. + * + * * Multisignature owner + * 0. `[writable]` The mint. + * 1. `[writable]` The account to mint tokens to. + * 2. `[]` The mint's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_MintTo, + /** + * Burns tokens by removing them from an account. `Burn` does not support accounts + * associated with the native mint, use `CloseAccount` instead. + * + * Accounts expected by this instruction: + * + * * Single owner/delegate + * 0. `[writable]` The account to burn from. + * 1. `[signer]` The account's owner/delegate. + * + * * Multisignature owner/delegate + * 0. `[writable]` The account to burn from. + * 1. `[]` The account's multisignature owner/delegate. + * 2. ..2+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_Burn, + /** + * Close an account by transferring all its SOL to the destination account. + * Non-native accounts may only be closed if its token amount is zero. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The account to close. + * 1. '[writable]' The destination account. + * 2. `[signer]` The account's owner. + * + * * Multisignature owner + * 0. `[writable]` The account to close. + * 1. '[writable]' The destination account. + * 2. `[]` The account's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_CloseAccount, +} Token_TokenInstruction_Tag; + +typedef struct Token_TokenInstruction_Token_InitializeMint_Body { + /** + * Initial amount of tokens to mint. + */ + uint64_t amount; + /** + * Number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_InitializeMint_Body; + +typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { + /** + * The number of signers (M) required to validate this multisignature account. + */ + uint8_t m; +} Token_TokenInstruction_Token_InitializeMultisig_Body; + +typedef struct Token_TokenInstruction_Token_Transfer_Body { + /** + * The amount of tokens to transfer. + */ + uint64_t amount; +} Token_TokenInstruction_Token_Transfer_Body; + +typedef struct Token_TokenInstruction_Token_Approve_Body { + /** + * The amount of tokens the delegate is approved for. + */ + uint64_t amount; +} Token_TokenInstruction_Token_Approve_Body; + +typedef struct Token_TokenInstruction_Token_MintTo_Body { + /** + * The amount of new tokens to mint. + */ + uint64_t amount; +} Token_TokenInstruction_Token_MintTo_Body; + +typedef struct Token_TokenInstruction_Token_Burn_Body { + /** + * The amount of tokens to burn. + */ + uint64_t amount; +} Token_TokenInstruction_Token_Burn_Body; + +typedef struct Token_TokenInstruction { + Token_TokenInstruction_Tag tag; + union { + Token_TokenInstruction_Token_InitializeMint_Body initialize_mint; + Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; + Token_TokenInstruction_Token_Transfer_Body transfer; + Token_TokenInstruction_Token_Approve_Body approve; + Token_TokenInstruction_Token_MintTo_Body mint_to; + Token_TokenInstruction_Token_Burn_Body burn; + }; +} Token_TokenInstruction; + +typedef uint8_t Token_Pubkey[32]; + +/** + * A C representation of Rust's `std::option::Option` + */ +typedef enum Token_COption_Pubkey_Tag { + /** + * No value + */ + Token_COption_Pubkey_None_Pubkey, + /** + * Some value `T` + */ + Token_COption_Pubkey_Some_Pubkey, +} Token_COption_Pubkey_Tag; + +typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { + Token_Pubkey _0; +} Token_COption_Pubkey_Token_Some_Body_Pubkey; + +typedef struct Token_COption_Pubkey { + Token_COption_Pubkey_Tag tag; + union { + Token_COption_Pubkey_Token_Some_Body_Pubkey some; + }; +} Token_COption_Pubkey; + +/** + * Mint data. + */ +typedef struct Token_Mint { + /** + * Optional owner, used to mint new tokens. The owner may only + * be provided during mint creation. If no owner is present then the mint + * has a fixed supply and no further tokens may be minted. + */ + Token_COption_Pubkey owner; + /** + * Number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; + /** + * Is `true` if this structure has been initialized + */ + bool is_initialized; +} Token_Mint; + +/** + * Account data. + */ +typedef struct Token_Account { + /** + * The mint associated with this account + */ + Token_Pubkey mint; + /** + * The owner of this account. + */ + Token_Pubkey owner; + /** + * The amount of tokens this account holds. + */ + uint64_t amount; + /** + * If `delegate` is `Some` then `delegated_amount` represents + * the amount authorized by the delegate + */ + Token_COption_Pubkey delegate; + /** + * Is `true` if this structure has been initialized + */ + bool is_initialized; + /** + * Is this a native token + */ + bool is_native; + /** + * The amount delegated + */ + uint64_t delegated_amount; +} Token_Account; + +/** + * Multisignature data. + */ +typedef struct Token_Multisig { + /** + * Number of signers required + */ + uint8_t m; + /** + * Number of valid signers + */ + uint8_t n; + /** + * Is `true` if this structure has been initialized + */ + bool is_initialized; + /** + * Signer public keys + */ + Token_Pubkey signers[Token_MAX_SIGNERS]; +} Token_Multisig; diff --git a/program/js/.eslintignore b/program/js/.eslintignore new file mode 100644 index 0000000..502167f --- /dev/null +++ b/program/js/.eslintignore @@ -0,0 +1 @@ +/lib diff --git a/program/js/.eslintrc.js b/program/js/.eslintrc.js new file mode 100644 index 0000000..96d3aae --- /dev/null +++ b/program/js/.eslintrc.js @@ -0,0 +1,56 @@ +// eslint-disable-next-line +module.exports = { + // eslint-disable-line import/no-commonjs + env: { + browser: true, + es6: true, + node: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + ], + parser: 'babel-eslint', + parserOptions: { + sourceType: 'module', + ecmaVersion: 8, + }, + rules: { + 'no-trailing-spaces': ['error'], + 'import/first': ['error'], + 'import/no-commonjs': ['error'], + 'import/order': [ + 'error', + { + groups: [ + ['internal', 'external', 'builtin'], + ['index', 'sibling', 'parent'], + ], + 'newlines-between': 'always', + }, + ], + indent: [ + 'error', + 2, + { + MemberExpression: 1, + SwitchCase: 1, + }, + ], + 'linebreak-style': ['error', 'unix'], + 'no-console': [0], + quotes: [ + 'error', + 'single', + {avoidEscape: true, allowTemplateLiterals: true}, + ], + 'require-await': ['error'], + semi: ['error', 'always'], + }, + settings: { + react: { + version: 'detect', + }, + }, +}; diff --git a/program/js/.flowconfig b/program/js/.flowconfig new file mode 100644 index 0000000..486f7e7 --- /dev/null +++ b/program/js/.flowconfig @@ -0,0 +1,20 @@ +[ignore] +/node_modules/* + +[include] + +[libs] +node_modules/@solana/web3.js/module.flow.js +flow-typed/ + +[options] + +emoji=true +esproposal.class_instance_fields=enable +esproposal.class_static_fields=enable +esproposal.decorators=ignore +esproposal.export_star_as=enable +module.system.node.resolve_dirname=./src +module.use_strict=true +experimental.const_params=true +include_warnings=true diff --git a/program/js/.gitignore b/program/js/.gitignore new file mode 100644 index 0000000..a65b417 --- /dev/null +++ b/program/js/.gitignore @@ -0,0 +1 @@ +lib diff --git a/program/js/.prettierrc.yaml b/program/js/.prettierrc.yaml new file mode 100644 index 0000000..8deef5d --- /dev/null +++ b/program/js/.prettierrc.yaml @@ -0,0 +1,7 @@ +arrowParens: "avoid" +bracketSpacing: false +jsxBracketSameLine: false +semi: true +singleQuote: true +tabWidth: 2 +trailingComma: "all" diff --git a/program/js/README.md b/program/js/README.md new file mode 100644 index 0000000..5deb943 --- /dev/null +++ b/program/js/README.md @@ -0,0 +1,69 @@ +# Token Javascript API + +The Token JavaScript library comprises: + +* A library to interact with the on-chain program +* A test client that exercises the program +* Scripts to facilitate building the program + +## Getting Started + +First fetch the npm dependencies, including `@solana/web3.js`, by running: +```bash +$ npm install +``` + +### Select a Network + +The client connects to a local Solana cluster by default. + +To enable on-chain program logs, set the `RUST_LOG` environment variable: + +```bash +$ export RUST_LOG=solana_runtime::native_loader=trace,solana_runtime::system_instruction_processor=trace,solana_runtime::bank=debug,solana_bpf_loader=debug,solana_rbpf=debug +``` + +To start a local Solana cluster run: +```bash +$ npm run localnet:update +$ npm run localnet:up +``` + +Solana cluster logs are available with: +```bash +$ npm run localnet:logs +``` + +For more details on working with a local cluster, see the [full +instructions](https://github.com/solana-labs/solana-web3.js#local-network). + +### Build the on-chain program + +```bash +$ npm run build:program +``` + +### Run the test client + +```bash +$ npm run start +``` + +## Pointing to a public Solana cluster + +Solana maintains three public clusters: +- `devnet` - Development cluster with airdrops enabled +- `testnet` - Tour De Sol test cluster without airdrops enabled +- `mainnet-beta` - Main cluster + +Use npm scripts to configure which cluster. + +To point to `devnet`: +```bash +$ npm run cluster:devnet +``` + +To point back to the local cluster: +```bash +$ npm run cluster:localnet +``` diff --git a/program/js/babel.config.json b/program/js/babel.config.json new file mode 100644 index 0000000..9c47e88 --- /dev/null +++ b/program/js/babel.config.json @@ -0,0 +1,17 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "targets": { + "node": "10" + } + } + ], + "@babel/preset-flow" + ], + "plugins": [ + "@babel/plugin-transform-runtime", + "@babel/plugin-proposal-class-properties" + ] +} diff --git a/program/js/babel.rollup.config.json b/program/js/babel.rollup.config.json new file mode 100644 index 0000000..ee7e695 --- /dev/null +++ b/program/js/babel.rollup.config.json @@ -0,0 +1,18 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "modules": false, + "targets": { + "node": "10" + } + } + ], + "@babel/preset-flow" + ], + "plugins": [ + "@babel/plugin-transform-runtime", + "@babel/plugin-proposal-class-properties" + ] +} diff --git a/program/js/cli/main.js b/program/js/cli/main.js new file mode 100644 index 0000000..ee36e4f --- /dev/null +++ b/program/js/cli/main.js @@ -0,0 +1,58 @@ +/** + * Exercises the token program + * + * @flow + */ + +import { + loadTokenProgram, + createMint, + createAccount, + transfer, + approveRevoke, + invalidApprove, + failOnApproveOverspend, + setOwner, + mintTo, + multisig, + burn, + failOnCloseAccount, + nativeToken, +} from './token-test'; + +async function main() { + console.log('Run test: loadTokenProgram'); + await loadTokenProgram(); + console.log('Run test: createMint'); + await createMint(); + console.log('Run test: createAccount'); + await createAccount(); + console.log('Run test: transfer'); + await transfer(); + console.log('Run test: approveRevoke'); + await approveRevoke(); + console.log('Run test: invalidApprove'); + await invalidApprove(); + console.log('Run test: failOnApproveOverspend'); + await failOnApproveOverspend(); + console.log('Run test: setOwner'); + await setOwner(); + console.log('Run test: mintTo'); + await mintTo(); + console.log('Run test: multisig'); + await multisig(); + console.log('Run test: burn'); + await burn(); + console.log('Run test: failOnCloseAccount'); + await failOnCloseAccount(); + console.log('Run test: nativeToken'); + await nativeToken(); + console.log('Success\n'); +} + +main() + .catch(err => { + console.error(err); + process.exit(-1); + }) + .then(() => process.exit()); diff --git a/program/js/cli/token-test.js b/program/js/cli/token-test.js new file mode 100644 index 0000000..c0523d9 --- /dev/null +++ b/program/js/cli/token-test.js @@ -0,0 +1,500 @@ +// @flow + +import fs from 'mz/fs'; +import {Account, Connection, BpfLoader, PublicKey} from '@solana/web3.js'; +import semver from 'semver'; + +import {Token, u64} from '../client/token'; +import {url} from '../url'; +import {newAccountWithLamports} from '../client/util/new-account-with-lamports'; +import {sleep} from '../client/util/sleep'; +import {Store} from '../client/util/store'; + +// Loaded token program's program id +let programId: PublicKey; + +// A token created by the next test and used by all subsequent tests +let mintOwner: Account; +let testToken: Token; +// Initial token account +let testAccountOwner: Account; +let testAccount: PublicKey; + +// A mintable token used by multiple tests +let mintableOwner: Account; +let testMintableToken: Token; +// Initial token account +let testMintableAccountOwner: Account; +let testMintableAccount: PublicKey; + +function assert(condition, message) { + if (!condition) { + console.log(Error().stack + ':token-test.js'); + throw message || 'Assertion failed'; + } +} + +async function didThrow(func, args): Promise { + try { + await func.apply(args); + } catch (e) { + return true; + } + return false; +} + +let connection; +async function getConnection(): Promise { + if (connection) return connection; + + let newConnection = new Connection(url, 'recent'); + const version = await newConnection.getVersion(); + + // commitment params are only supported >= 0.21.0 + const solanaCoreVersion = version['solana-core'].split(' ')[0]; + if (semver.gte(solanaCoreVersion, '0.21.0')) { + newConnection = new Connection(url, 'recent'); + } + + // eslint-disable-next-line require-atomic-updates + connection = newConnection; + console.log('Connection to cluster established:', url, version); + return connection; +} + +async function loadProgram( + connection: Connection, + path: string, +): Promise { + const NUM_RETRIES = 500; /* allow some number of retries */ + const data = await fs.readFile(path); + const {feeCalculator} = await connection.getRecentBlockhash(); + const balanceNeeded = + feeCalculator.lamportsPerSignature * + (BpfLoader.getMinNumSignatures(data.length) + NUM_RETRIES) + + (await connection.getMinimumBalanceForRentExemption(data.length)); + + const from = await newAccountWithLamports(connection, balanceNeeded); + const program_account = new Account(); + console.log('Loading program:', path); + await BpfLoader.load(connection, from, program_account, data); + return program_account.publicKey; +} + +async function GetPrograms(connection: Connection): Promise { + const store = new Store(); + let tokenProgramId = null; + try { + const config = await store.load('config.json'); + console.log('Using pre-loaded Token program'); + console.log( + ' Note: To reload program remove client/util/store/config.json', + ); + tokenProgramId = new PublicKey(config.tokenProgramId); + } catch (err) { + tokenProgramId = await loadProgram( + connection, + '../../target/bpfel-unknown-unknown/release/spl_token.so', + ); + await store.save('config.json', { + tokenProgramId: tokenProgramId.toString(), + }); + } + return tokenProgramId; +} + +export async function loadTokenProgram(): Promise { + const connection = await getConnection(); + programId = await GetPrograms(connection); + + console.log('Token Program ID', programId.toString()); +} + +export async function createMint(): Promise { + const connection = await getConnection(); + const payer = await newAccountWithLamports( + connection, + 100000000000 /* wag */, + ); + mintOwner = new Account(); + testAccountOwner = new Account(); + [testToken, testAccount] = await Token.createMint( + connection, + payer, + mintOwner.publicKey, + testAccountOwner.publicKey, + new u64(10000), + 2, + programId, + false, + ); + + const mintInfo = await testToken.getMintInfo(); + assert(mintInfo.decimals == 2); + assert(mintInfo.owner == null); + + const accountInfo = await testToken.getAccountInfo(testAccount); + assert(accountInfo.mint.equals(testToken.publicKey)); + assert(accountInfo.owner.equals(testAccountOwner.publicKey)); + assert(accountInfo.amount.toNumber() == 10000); + assert(accountInfo.delegate == null); + assert(accountInfo.delegatedAmount.toNumber() == 0); +} + +export async function createAccount(): Promise { + const destOwner = new Account(); + const account = await testToken.createAccount(destOwner.publicKey); + const accountInfo = await testToken.getAccountInfo(account); + assert(accountInfo.mint.equals(testToken.publicKey)); + assert(accountInfo.owner.equals(destOwner.publicKey)); + assert(accountInfo.amount.toNumber() == 0); + assert(accountInfo.delegate == null); +} + +export async function transfer(): Promise { + const destOwner = new Account(); + const dest = await testToken.createAccount(destOwner.publicKey); + + await testToken.transfer(testAccount, dest, testAccountOwner, [], 123); + await sleep(500); + + let destAccountInfo = await testToken.getAccountInfo(dest); + assert(destAccountInfo.amount.toNumber() == 123); +} + +export async function approveRevoke(): Promise { + if (programId == null) { + console.log('test skipped, requires "load token program" to succeed'); + return; + } + + const delegate = new PublicKey(); + await testToken.approve(testAccount, delegate, testAccountOwner, [], 456); + let testAccountInfo = await testToken.getAccountInfo(testAccount); + assert(testAccountInfo.delegatedAmount.toNumber() == 456); + if (testAccountInfo.delegate === null) { + throw new Error('deleage should not be null'); + } else { + assert(testAccountInfo.delegate.equals(delegate)); + } + + await testToken.revoke(testAccount, testAccountOwner, []); + testAccountInfo = await testToken.getAccountInfo(testAccount); + assert(testAccountInfo.delegatedAmount.toNumber() == 0); + if (testAccountInfo.delegate != null) { + throw new Error('delegate should be null'); + } +} + +export async function invalidApprove(): Promise { + const owner = new Account(); + const account1 = await testToken.createAccount(owner.publicKey); + const account2 = await testToken.createAccount(owner.publicKey); + const delegate = new Account(); + + // account2 is not a delegate account of account1 + assert(didThrow(testToken.approve, [account1, account2, owner, [], 123])); + // account1Delegate is not a delegate account of account2 + assert(didThrow(testToken.approve, [account2, delegate, owner, [], 123])); +} + +export async function failOnApproveOverspend(): Promise { + const owner = new Account(); + const account1 = await testToken.createAccount(owner.publicKey); + const account2 = await testToken.createAccount(owner.publicKey); + const delegate = new Account(); + + await testToken.transfer(testAccount, account1, testAccountOwner, [], 10); + + await testToken.approve(account1, delegate.publicKey, owner, [], 2); + + let account1Info = await testToken.getAccountInfo(account1); + assert(account1Info.amount.toNumber() == 10); + assert(account1Info.delegatedAmount.toNumber() == 2); + if (account1Info.delegate === null) { + throw new Error('deleage should not be null'); + } else { + assert(account1Info.delegate.equals(delegate.publicKey)); + } + + await testToken.transfer(account1, account2, delegate, [], 1); + + account1Info = await testToken.getAccountInfo(account1); + assert(account1Info.amount.toNumber() == 9); + assert(account1Info.delegatedAmount.toNumber() == 1); + + await testToken.transfer(account1, account2, delegate, [], 1); + + account1Info = await testToken.getAccountInfo(account1); + assert(account1Info.amount.toNumber() == 8); + assert(account1Info.delegate === null); + assert(account1Info.delegatedAmount.toNumber() == 0); + + assert(didThrow(testToken.transfer, [account1, account2, delegate, [], 1])); +} + +export async function setOwner(): Promise { + const owner = new Account(); + const newOwner = new Account(); + const owned = await testToken.createAccount(owner.publicKey); + + await testToken.setOwner(owned, newOwner.publicKey, owner, []); + assert(didThrow(testToken.setOwner, [owned, newOwner.publicKey, owner, []])); + await testToken.setOwner(owned, owner.publicKey, newOwner, []); +} + +export async function mintTo(): Promise { + const connection = await getConnection(); + const payer = await newAccountWithLamports( + connection, + 100000000000 /* wag */, + ); + mintableOwner = new Account(); + testMintableAccountOwner = new Account(); + [testMintableToken, testMintableAccount] = await Token.createMint( + connection, + payer, + mintableOwner.publicKey, + testMintableAccountOwner.publicKey, + new u64(10000), + 2, + programId, + true, + ); + + { + const mintInfo = await testMintableToken.getMintInfo(); + assert(mintInfo.decimals == 2); + if (mintInfo.owner === null) { + throw new Error('owner should not be null'); + } else { + assert(mintInfo.owner.equals(mintableOwner.publicKey)); + } + + const accountInfo = await testMintableToken.getAccountInfo( + testMintableAccount, + ); + assert(accountInfo.mint.equals(testMintableToken.publicKey)); + assert(accountInfo.owner.equals(testMintableAccountOwner.publicKey)); + assert(accountInfo.amount.toNumber() == 10000); + assert(accountInfo.delegate == null); + assert(accountInfo.delegatedAmount.toNumber() == 0); + } + + const dest = await testMintableToken.createAccount( + testMintableAccountOwner.publicKey, + ); + await testMintableToken.mintTo(dest, mintableOwner, [], 42); + + { + const mintInfo = await testMintableToken.getMintInfo(); + assert(mintInfo.decimals == 2); + if (mintInfo.owner === null) { + throw new Error('owner should not be null'); + } else { + assert(mintInfo.owner.equals(mintableOwner.publicKey)); + } + + const accountInfo = await testMintableToken.getAccountInfo(dest); + assert(accountInfo.mint.equals(testMintableToken.publicKey)); + assert(accountInfo.owner.equals(testMintableAccountOwner.publicKey)); + assert(accountInfo.amount.toNumber() == 42); + assert(accountInfo.delegate == null); + assert(accountInfo.delegatedAmount.toNumber() == 0); + } +} + +export async function burn(): Promise { + let accountInfo = await testToken.getAccountInfo(testAccount); + const amount = accountInfo.amount.toNumber(); + + await testToken.burn(testAccount, testAccountOwner, [], 1); + await sleep(500); + + accountInfo = await testToken.getAccountInfo(testAccount); + assert(accountInfo.amount.toNumber() == amount - 1); +} + +export async function multisig(): Promise { + const m = 2; + const n = 5; + + let signerAccounts = []; + for (var i = 0; i < n; i++) { + signerAccounts.push(new Account()); + } + let signerPublicKeys = []; + signerAccounts.forEach(account => signerPublicKeys.push(account.publicKey)); + const multisig = await testToken.createMultisig(m, signerPublicKeys); + + const multisigInfo = await testToken.getMultisigInfo(multisig); + assert(multisigInfo.m === m); + assert(multisigInfo.n === n); + assert(multisigInfo.signer1.equals(signerPublicKeys[0])); + assert(multisigInfo.signer2.equals(signerPublicKeys[1])); + assert(multisigInfo.signer3.equals(signerPublicKeys[2])); + assert(multisigInfo.signer4.equals(signerPublicKeys[3])); + assert(multisigInfo.signer5.equals(signerPublicKeys[4])); + + const multisigOwnedAccount = await testToken.createAccount(multisig); + const finalDest = await testToken.createAccount(multisig); + await testToken.transfer( + testAccount, + multisigOwnedAccount, + testAccountOwner, + [], + 2, + ); + + // Transfer via multisig + await testToken.transfer( + multisigOwnedAccount, + finalDest, + multisig, + signerAccounts, + 1, + ); + await sleep(500); + let accountInfo = await testToken.getAccountInfo(finalDest); + assert(accountInfo.amount.toNumber() == 1); + + // Approve via multisig + { + const delegate = new PublicKey(); + await testToken.approve( + multisigOwnedAccount, + delegate, + multisig, + signerAccounts, + 1, + ); + const accountInfo = await testToken.getAccountInfo(multisigOwnedAccount); + assert(accountInfo.delegate != null); + if (accountInfo.delegate != null) { + assert(accountInfo.delegate.equals(delegate)); + assert(accountInfo.delegatedAmount.toNumber() == 1); + } + } + + // MintTo via multisig + { + let accountInfo = await testMintableToken.getAccountInfo( + testMintableAccount, + ); + const initialAmount = accountInfo.amount.toNumber(); + await testMintableToken.setOwner( + testMintableToken.publicKey, + multisig, + mintableOwner, + [], + ); + await testMintableToken.mintTo( + testMintableAccount, + multisig, + signerAccounts, + 42, + ); + accountInfo = await testMintableToken.getAccountInfo(testMintableAccount); + assert(accountInfo.amount.toNumber() == initialAmount + 42); + } + + // SetOwner of mint via multisig + { + await testMintableToken.setOwner( + testMintableToken.publicKey, + mintableOwner.publicKey, + multisig, + signerAccounts, + ); + const mintInfo = await testMintableToken.getMintInfo(); + assert(mintInfo.owner != null); + if (mintInfo.owner != null) { + assert(mintInfo.owner.equals(mintableOwner.publicKey)); + } + } + + // SetOwner of account via multisig + { + const newOwner = new PublicKey(); + await testToken.setOwner( + multisigOwnedAccount, + newOwner, + multisig, + signerAccounts, + ); + const accountInfo = await testToken.getAccountInfo(multisigOwnedAccount); + assert(accountInfo.owner.equals(newOwner)); + } +} + +export async function failOnCloseAccount(): Promise { + const connection = await getConnection(); + const owner = new Account(); + const close = await testToken.createAccount(owner.publicKey); + + let close_balance; + let info = await connection.getAccountInfo(close); + if (info != null) { + close_balance = info.lamports; + } else { + throw new Error('Account not found'); + } + + // Initialize destination account to isolate source of failure + const balanceNeeded = await connection.getMinimumBalanceForRentExemption(0); + const dest = await newAccountWithLamports(connection, balanceNeeded); + + info = await connection.getAccountInfo(dest.publicKey); + if (info != null) { + assert(info.lamports == balanceNeeded); + } else { + throw new Error('Account not found'); + } + + assert(didThrow(testToken.closeAccount, [close, dest.publicKey, owner, []])); + + info = await connection.getAccountInfo(close); + if (info != null) { + assert(info.lamports == close_balance); + } else { + throw new Error('Account not found'); + } +} + +export async function nativeToken(): Promise { + const connection = await getConnection(); + + const mintPublicKey = new PublicKey( + 'So11111111111111111111111111111111111111111', + ); + const payer = await newAccountWithLamports( + connection, + 100000000000 /* wag */, + ); + const token = new Token(connection, mintPublicKey, programId, payer); + const owner = new Account(); + const native = await token.createAccount(owner.publicKey); + let accountInfo = await token.getAccountInfo(native); + assert(accountInfo.isNative); + let balance; + let info = await connection.getAccountInfo(native); + if (info != null) { + balance = info.lamports; + } else { + throw new Error('Account not found'); + } + + const balanceNeeded = await connection.getMinimumBalanceForRentExemption(0); + const dest = await newAccountWithLamports(connection, balanceNeeded); + await token.closeAccount(native, dest.publicKey, owner, []); + info = await connection.getAccountInfo(native); + if (info != null) { + throw new Error('Account not burned'); + } + info = await connection.getAccountInfo(dest.publicKey); + if (info != null) { + assert(info.lamports == balanceNeeded + balance); + } else { + throw new Error('Account not found'); + } +} diff --git a/program/js/client/layout.js b/program/js/client/layout.js new file mode 100644 index 0000000..6c3e06b --- /dev/null +++ b/program/js/client/layout.js @@ -0,0 +1,47 @@ +// @flow + +import * as BufferLayout from 'buffer-layout'; + +/** + * Layout for a public key + */ +export const publicKey = (property: string = 'publicKey'): Object => { + return BufferLayout.blob(32, property); +}; + +/** + * Layout for a 64bit unsigned value + */ +export const uint64 = (property: string = 'uint64'): Object => { + return BufferLayout.blob(8, property); +}; + +/** + * Layout for a Rust String type + */ +export const rustString = (property: string = 'string') => { + const rsl = BufferLayout.struct( + [ + BufferLayout.u32('length'), + BufferLayout.u32('lengthPadding'), + BufferLayout.blob(BufferLayout.offset(BufferLayout.u32(), -8), 'chars'), + ], + property, + ); + const _decode = rsl.decode.bind(rsl); + const _encode = rsl.encode.bind(rsl); + + rsl.decode = (buffer, offset) => { + const data = _decode(buffer, offset); + return data.chars.toString('utf8'); + }; + + rsl.encode = (str, buffer, offset) => { + const data = { + chars: Buffer.from(str, 'utf8'), + }; + return _encode(data, buffer, offset); + }; + + return rsl; +}; diff --git a/program/js/client/token.js b/program/js/client/token.js new file mode 100644 index 0000000..e59a2ab --- /dev/null +++ b/program/js/client/token.js @@ -0,0 +1,1242 @@ +/** + * @flow + */ + +import assert from 'assert'; +import BN from 'bn.js'; +import * as BufferLayout from 'buffer-layout'; +import { + Account, + PublicKey, + SystemProgram, + Transaction, + TransactionInstruction, +} from '@solana/web3.js'; +import type {Connection, TransactionSignature} from '@solana/web3.js'; + +import * as Layout from './layout'; +import {sendAndConfirmTransaction} from './util/send-and-confirm-transaction'; + +/** + * 64-bit value + */ +export class u64 extends BN { + /** + * Convert to Buffer representation + */ + toBuffer(): Buffer { + const a = super.toArray().reverse(); + const b = Buffer.from(a); + if (b.length === 8) { + return b; + } + assert(b.length < 8, 'u64 too large'); + + const zeroPad = Buffer.alloc(8); + b.copy(zeroPad); + return zeroPad; + } + + /** + * Construct a u64 from Buffer representation + */ + static fromBuffer(buffer: Buffer): u64 { + assert(buffer.length === 8, `Invalid buffer length: ${buffer.length}`); + return new BN( + [...buffer] + .reverse() + .map(i => `00${i.toString(16)}`.slice(-2)) + .join(''), + 16, + ); + } +} + +function isAccount(accountOrPublicKey: any): boolean { + return 'publicKey' in accountOrPublicKey; +} + +/** + * Information about the mint + */ +type MintInfo = {| + /** + * Owner of the mint, given authority to mint new tokens + */ + owner: null | PublicKey, + + /** + * Number of base 10 digits to the right of the decimal place + */ + decimals: number, + + /** + * Is this mint initialized + */ + initialized: boolean, +|}; + +const MintLayout = BufferLayout.struct([ + BufferLayout.u32('option'), + Layout.publicKey('owner'), + BufferLayout.u8('decimals'), + BufferLayout.u8('is_initialized'), + BufferLayout.u16('padding'), +]); + +/** + * Information about an account + */ +type AccountInfo = {| + /** + * The mint associated with this account + */ + mint: PublicKey, + + /** + * Owner of this account + */ + owner: PublicKey, + + /** + * Amount of tokens this account holds + */ + amount: u64, + + /** + * The delegate for this account + */ + delegate: null | PublicKey, + + /** + * The amount of tokens the delegate authorized to the delegate + */ + delegatedAmount: u64, + + /** + * Is this account initialized + */ + isInitialized: boolean, + + /** + * Is this a native token account + */ + isNative: boolean, +|}; + +/** + * @private + */ +const AccountLayout = BufferLayout.struct([ + Layout.publicKey('mint'), + Layout.publicKey('owner'), + Layout.uint64('amount'), + BufferLayout.u32('option'), + Layout.publicKey('delegate'), + BufferLayout.u8('is_initialized'), + BufferLayout.u8('is_native'), + BufferLayout.u16('padding'), + Layout.uint64('delegatedAmount'), +]); + +/** + * Information about an multisig + */ +type MultisigInfo = {| + /** + * The number of signers required + */ + m: number, + + /** + * Number of possible signers, corresponds to the + * number of `signers` that are valid. + */ + n: number, + + /** + * Is this mint initialized + */ + initialized: boolean, + + /** + * The signers + */ + signer1: PublicKey, + signer2: PublicKey, + signer3: PublicKey, + signer4: PublicKey, + signer5: PublicKey, + signer6: PublicKey, + signer7: PublicKey, + signer8: PublicKey, + signer9: PublicKey, + signer10: PublicKey, + signer11: PublicKey, +|}; + +/** + * @private + */ +const MultisigLayout = BufferLayout.struct([ + BufferLayout.u8('m'), + BufferLayout.u8('n'), + BufferLayout.u8('is_initialized'), + Layout.publicKey('signer1'), + Layout.publicKey('signer2'), + Layout.publicKey('signer3'), + Layout.publicKey('signer4'), + Layout.publicKey('signer5'), + Layout.publicKey('signer6'), + Layout.publicKey('signer7'), + Layout.publicKey('signer8'), + Layout.publicKey('signer9'), + Layout.publicKey('signer10'), + Layout.publicKey('signer11'), +]); + +type TokenAndPublicKey = [Token, PublicKey]; // This type exists to workaround an esdoc parse error + +/** + * An ERC20-like Token + */ +export class Token { + /** + * @private + */ + connection: Connection; + + /** + * The public key identifying this mint + */ + publicKey: PublicKey; + + /** + * Program Identifier for the Token program + */ + programId: PublicKey; + + /** + * Fee payer + */ + payer: Account; + + /** + * Create a Token object attached to the specific mint + * + * @param connection The connection to use + * @param token Public key of the mint + * @param programId token programId + * @param payer Payer of fees + */ + constructor( + connection: Connection, + publicKey: PublicKey, + programId: PublicKey, + payer: Account, + ) { + Object.assign(this, {connection, publicKey, programId, payer}); + } + + /** + * Get the minimum balance for the mint to be rent exempt + * + * @return Number of lamports required + */ + static async getMinBalanceRentForExemptMint( + connection: Connection, + ): Promise { + return await connection.getMinimumBalanceForRentExemption(MintLayout.span); + } + + /** + * Get the minimum balance for the account to be rent exempt + * + * @return Number of lamports required + */ + static async getMinBalanceRentForExemptAccount( + connection: Connection, + ): Promise { + return await connection.getMinimumBalanceForRentExemption( + AccountLayout.span, + ); + } + + /** + * Get the minimum balance for the multsig to be rent exempt + * + * @return Number of lamports required + */ + static async getMinBalanceRentForExemptMultisig( + connection: Connection, + ): Promise { + return await connection.getMinimumBalanceForRentExemption( + MultisigLayout.span, + ); + } + + /** + * Creates and initializes a token. + * + * @param connection The connection to use + * @param owner User account that will own the returned account + * @param supply Initial supply to mint + * @param decimals Location of the decimal place + * @param programId Optional token programId, uses the system programId by default + * @return Token object for the newly minted token, Public key of the account + * holding the total amount of new tokens + */ + static async createMint( + connection: Connection, + payer: Account, + mintOwner: PublicKey, + accountOwner: PublicKey, + supply: u64, + decimals: number, + programId: PublicKey, + is_owned: boolean = false, + ): Promise { + let transaction; + const mintAccount = new Account(); + const token = new Token( + connection, + mintAccount.publicKey, + programId, + payer, + ); + const initialAccountPublicKey = await token.createAccount(accountOwner); + + // Allocate memory for the account + const balanceNeeded = await Token.getMinBalanceRentForExemptMint( + connection, + ); + transaction = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: mintAccount.publicKey, + lamports: balanceNeeded, + space: MintLayout.span, + programId, + }); + + // Create the mint + let keys = [ + {pubkey: mintAccount.publicKey, isSigner: false, isWritable: true}, + ]; + if (supply.toNumber() != 0) { + keys.push({ + pubkey: initialAccountPublicKey, + isSigner: false, + isWritable: true, + }); + } + if (is_owned) { + keys.push({pubkey: mintOwner, isSigner: false, isWritable: false}); + } + const commandDataLayout = BufferLayout.struct([ + BufferLayout.u8('instruction'), + Layout.uint64('supply'), + BufferLayout.u8('decimals'), + ]); + let data = Buffer.alloc(1024); + { + const encodeLength = commandDataLayout.encode( + { + instruction: 0, // InitializeMint instruction + supply: supply.toBuffer(), + decimals, + }, + data, + ); + data = data.slice(0, encodeLength); + } + transaction.add({ + keys, + programId, + data, + }); + + // Send the two instructions + await sendAndConfirmTransaction( + 'createAccount and InitializeMint', + connection, + transaction, + payer, + mintAccount, + ); + + return [token, initialAccountPublicKey]; + } + + /** + * Create and initializes a new account. + * + * This account may then be used as a `transfer()` or `approve()` destination + * + * @param owner User account that will own the new account + * @return Public key of the new empty account + */ + async createAccount(owner: PublicKey): Promise { + const mintAccount = new Account(); + let transaction; + + // Allocate memory for the account + const balanceNeeded = await Token.getMinBalanceRentForExemptAccount( + this.connection, + ); + transaction = SystemProgram.createAccount({ + fromPubkey: this.payer.publicKey, + newAccountPubkey: mintAccount.publicKey, + lamports: balanceNeeded, + space: AccountLayout.span, + programId: this.programId, + }); + + // create the new account + const keys = [ + {pubkey: mintAccount.publicKey, isSigner: false, isWritable: true}, + {pubkey: this.publicKey, isSigner: false, isWritable: false}, + {pubkey: owner, isSigner: false, isWritable: false}, + ]; + const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]); + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 1, // InitializeAccount instruction + }, + data, + ); + transaction.add({ + keys, + programId: this.programId, + data, + }); + + // Send the two instructions + await sendAndConfirmTransaction( + 'createAccount and InitializeAccount', + this.connection, + transaction, + this.payer, + mintAccount, + ); + + return mintAccount.publicKey; + } + + /** + * Create and initializes a new multisig. + * + * This account may then be used for multisignature verification + * + * @param owner User account that will own the multsig account + * @return Public key of the new multisig account + */ + async createMultisig( + m: number, + signers: Array, + ): Promise { + const multisigAccount = new Account(); + let transaction; + + // Allocate memory for the account + const balanceNeeded = await Token.getMinBalanceRentForExemptMultisig( + this.connection, + ); + transaction = SystemProgram.createAccount({ + fromPubkey: this.payer.publicKey, + newAccountPubkey: multisigAccount.publicKey, + lamports: balanceNeeded, + space: MultisigLayout.span, + programId: this.programId, + }); + + // create the new account + let keys = [ + {pubkey: multisigAccount.publicKey, isSigner: false, isWritable: true}, + ]; + signers.forEach(signer => + keys.push({pubkey: signer, isSigner: false, isWritable: false}), + ); + const dataLayout = BufferLayout.struct([ + BufferLayout.u8('instruction'), + BufferLayout.u8('m'), + ]); + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 2, // InitializeM { + const info = await this.connection.getAccountInfo(this.publicKey); + if (info === null) { + throw new Error('Failed to find mint account'); + } + if (!info.owner.equals(this.programId)) { + throw new Error(`Invalid mint owner: ${JSON.stringify(info.owner)}`); + } + if (info.data.length != MintLayout.span) { + throw new Error(`Invalid mint size`); + } + + const data = Buffer.from(info.data); + const mintInfo = MintLayout.decode(data); + if (mintInfo.option === 0) { + mintInfo.owner = null; + } else { + mintInfo.owner = new PublicKey(mintInfo.owner); + } + return mintInfo; + } + + /** + * Retrieve account information + * + * @param account Public key of the account + */ + async getAccountInfo(account: PublicKey): Promise { + const info = await this.connection.getAccountInfo(account); + if (info === null) { + throw new Error('Failed to find account'); + } + if (!info.owner.equals(this.programId)) { + throw new Error(`Invalid account owner`); + } + if (info.data.length != AccountLayout.span) { + throw new Error(`Invalid account size`); + } + + const data = Buffer.from(info.data); + const accountInfo = AccountLayout.decode(data); + accountInfo.mint = new PublicKey(accountInfo.mint); + accountInfo.owner = new PublicKey(accountInfo.owner); + accountInfo.amount = u64.fromBuffer(accountInfo.amount); + accountInfo.isInitialized = accountInfo.isInitialized != 0; + accountInfo.isNative = accountInfo.isNative != 0; + if (accountInfo.option === 0) { + accountInfo.delegate = null; + accountInfo.delegatedAmount = new u64(); + } else { + accountInfo.delegate = new PublicKey(accountInfo.delegate); + accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount); + } + + if (!accountInfo.mint.equals(this.publicKey)) { + throw new Error( + `Invalid account mint: ${JSON.stringify( + accountInfo.mint, + )} !== ${JSON.stringify(this.publicKey)}`, + ); + } + return accountInfo; + } + + /** + * Retrieve Multisig information + * + * @param multisig Public key of the account + */ + async getMultisigInfo(multisig: PublicKey): Promise { + const info = await this.connection.getAccountInfo(multisig); + if (info === null) { + throw new Error('Failed to find multisig'); + } + if (!info.owner.equals(this.programId)) { + throw new Error(`Invalid multisig owner`); + } + if (info.data.length != MultisigLayout.span) { + throw new Error(`Invalid multisig size`); + } + + const data = Buffer.from(info.data); + const multisigInfo = MultisigLayout.decode(data); + multisigInfo.signer1 = new PublicKey(multisigInfo.signer1); + multisigInfo.signer2 = new PublicKey(multisigInfo.signer2); + multisigInfo.signer3 = new PublicKey(multisigInfo.signer3); + multisigInfo.signer4 = new PublicKey(multisigInfo.signer4); + multisigInfo.signer5 = new PublicKey(multisigInfo.signer5); + multisigInfo.signer6 = new PublicKey(multisigInfo.signer6); + multisigInfo.signer7 = new PublicKey(multisigInfo.signer7); + multisigInfo.signer8 = new PublicKey(multisigInfo.signer8); + multisigInfo.signer9 = new PublicKey(multisigInfo.signer9); + multisigInfo.signer10 = new PublicKey(multisigInfo.signer10); + multisigInfo.signer11 = new PublicKey(multisigInfo.signer11); + + return multisigInfo; + } + + /** + * Transfer tokens to another account + * + * @param source Source account + * @param destination Destination account + * @param authority Owner of the source account + * @param multiSigners Signing accounts if `authority` is a multiSig + * @param amount Number of tokens to transfer + */ + async transfer( + source: PublicKey, + destination: PublicKey, + authority: any, + multiSigners: Array, + amount: number | u64, + ): Promise { + let ownerPublicKey; + let signers; + if (isAccount(authority)) { + ownerPublicKey = authority.publicKey; + signers = [authority]; + } else { + ownerPublicKey = authority; + signers = multiSigners; + } + return await sendAndConfirmTransaction( + 'Transfer', + this.connection, + new Transaction().add( + Token.createTransferInstruction( + this.programId, + source, + destination, + ownerPublicKey, + multiSigners, + amount, + ), + ), + this.payer, + ...signers, + ); + } + + /** + * Grant a third-party permission to transfer up the specified number of tokens from an account + * + * @param account Public key of the account + * @param delegate Account authorized to perform a transfer tokens from the source account + * @param owner Owner of the source account + * @param multiSigners Signing accounts if `owner` is a multiSig + * @param amount Maximum number of tokens the delegate may transfer + */ + async approve( + account: PublicKey, + delegate: PublicKey, + owner: any, + multiSigners: Array, + amount: number | u64, + ): Promise { + let ownerPublicKey; + let signers; + if (isAccount(owner)) { + ownerPublicKey = owner.publicKey; + signers = [owner]; + } else { + ownerPublicKey = owner; + signers = multiSigners; + } + await sendAndConfirmTransaction( + 'Approve', + this.connection, + new Transaction().add( + Token.createApproveInstruction( + this.programId, + account, + delegate, + ownerPublicKey, + multiSigners, + amount, + ), + ), + this.payer, + ...signers, + ); + } + + /** + * Remove approval for the transfer of any remaining tokens + * + * @param account Public key of the account + * @param owner Owner of the source account + * @param multiSigners Signing accounts if `owner` is a multiSig + */ + async revoke( + account: PublicKey, + owner: any, + multiSigners: Array, + ): Promise { + let ownerPublicKey; + let signers; + if (isAccount(owner)) { + ownerPublicKey = owner.publicKey; + signers = [owner]; + } else { + ownerPublicKey = owner; + signers = multiSigners; + } + await sendAndConfirmTransaction( + 'Revoke', + this.connection, + new Transaction().add( + Token.createRevokeInstruction( + this.programId, + account, + ownerPublicKey, + multiSigners, + ), + ), + this.payer, + ...signers, + ); + } + + /** + * Assign a new owner to the account + * + * @param account Public key of the account + * @param newOwner New owner of the account + * @param owner Owner of the account + * @param multiSigners Signing accounts if `owner` is a multiSig + */ + async setOwner( + owned: PublicKey, + newOwner: PublicKey, + owner: any, + multiSigners: Array, + ): Promise { + let ownerPublicKey; + let signers; + if (isAccount(owner)) { + ownerPublicKey = owner.publicKey; + signers = [owner]; + } else { + ownerPublicKey = owner; + signers = multiSigners; + } + await sendAndConfirmTransaction( + 'SetOwner', + this.connection, + new Transaction().add( + Token.createSetOwnerInstruction( + this.programId, + owned, + newOwner, + ownerPublicKey, + multiSigners, + ), + ), + this.payer, + ...signers, + ); + } + + /** + * Mint new tokens + * + * @param mint Public key of the mint + * @param dest Public key of the account to mint to + * @param authority Owner of the mint + * @param multiSigners Signing accounts if `authority` is a multiSig + * @param amount ammount to mint + */ + async mintTo( + dest: PublicKey, + authority: any, + multiSigners: Array, + amount: number, + ): Promise { + let ownerPublicKey; + let signers; + if (isAccount(authority)) { + ownerPublicKey = authority.publicKey; + signers = [authority]; + } else { + ownerPublicKey = authority; + signers = multiSigners; + } + await sendAndConfirmTransaction( + 'MintTo', + this.connection, + new Transaction().add( + Token.createMintToInstruction( + this.programId, + this.publicKey, + dest, + ownerPublicKey, + multiSigners, + amount, + ), + ), + this.payer, + ...signers, + ); + } + + /** + * Burn tokens + * + * @param account Account to burn tokens from + * @param authority Public key account owner + * @param multiSigners Signing accounts if `authority` is a multiSig + * @param amount ammount to burn + */ + async burn( + account: PublicKey, + authority: any, + multiSigners: Array, + amount: number, + ): Promise { + let ownerPublicKey; + let signers; + if (isAccount(authority)) { + ownerPublicKey = authority.publicKey; + signers = [authority]; + } else { + ownerPublicKey = authority; + signers = multiSigners; + } + await sendAndConfirmTransaction( + 'Burn', + this.connection, + new Transaction().add( + Token.createBurnInstruction( + this.programId, + account, + ownerPublicKey, + multiSigners, + amount, + ), + ), + this.payer, + ...signers, + ); + } + + /** + * Burn account + * + * @param account Account to burn + * @param authority account owner + * @param multiSigners Signing accounts if `owner` is a multiSig + */ + async closeAccount( + account: PublicKey, + dest: PublicKey, + owner: any, + multiSigners: Array, + ): Promise { + let ownerPublicKey; + let signers; + if (isAccount(owner)) { + ownerPublicKey = owner.publicKey; + signers = [owner]; + } else { + ownerPublicKey = owner; + signers = multiSigners; + } + await sendAndConfirmTransaction( + 'CloseAccount', + this.connection, + new Transaction().add( + Token.createCloseAccountInstruction( + this.programId, + account, + dest, + ownerPublicKey, + multiSigners, + ), + ), + this.payer, + ...signers, + ); + } + + /** + * Construct a Transfer instruction + * + * @param source Source account + * @param destination Destination account + * @param authority Owner of the source account + * @param multiSigners Signing accounts if `authority` is a multiSig + * @param amount Number of tokens to transfer + */ + static createTransferInstruction( + programId: PublicKey, + source: PublicKey, + destination: PublicKey, + authority: any, + multiSigners: Array, + amount: number | u64, + ): TransactionInstruction { + const dataLayout = BufferLayout.struct([ + BufferLayout.u8('instruction'), + Layout.uint64('amount'), + ]); + + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 3, // Transfer instruction + amount: new u64(amount).toBuffer(), + }, + data, + ); + + let keys = [ + {pubkey: source, isSigner: false, isWritable: true}, + {pubkey: destination, isSigner: false, isWritable: true}, + ]; + if (isAccount(authority)) { + keys.push({ + pubkey: authority.publicKey, + isSigner: true, + isWritable: false, + }); + } else { + keys.push({pubkey: authority, isSigner: false, isWritable: false}); + multiSigners.forEach(signer => + keys.push({ + pubkey: signer.publicKey, + isSigner: true, + isWritable: false, + }), + ); + } + return new TransactionInstruction({ + keys, + programId: programId, + data, + }); + } + + /** + * Construct an Approve instruction + * + * @param account Public key of the account + * @param delegate Account authorized to perform a transfer of tokens from the source account + * @param owner Owner of the source account + * @param multiSigners Signing accounts if `owner` is a multiSig + * @param amount Maximum number of tokens the delegate may transfer + */ + static createApproveInstruction( + programId: PublicKey, + account: PublicKey, + delegate: PublicKey, + owner: any, + multiSigners: Array, + amount: number | u64, + ): TransactionInstruction { + const dataLayout = BufferLayout.struct([ + BufferLayout.u8('instruction'), + Layout.uint64('amount'), + ]); + + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 4, // Approve instruction + amount: new u64(amount).toBuffer(), + }, + data, + ); + + let keys = [ + {pubkey: account, isSigner: false, isWritable: true}, + {pubkey: delegate, isSigner: false, isWritable: false}, + ]; + if (isAccount(owner)) { + keys.push({pubkey: owner.publicKey, isSigner: true, isWritable: false}); + } else { + keys.push({pubkey: owner, isSigner: false, isWritable: false}); + multiSigners.forEach(signer => + keys.push({ + pubkey: signer.publicKey, + isSigner: true, + isWritable: false, + }), + ); + } + + return new TransactionInstruction({ + keys, + programId: programId, + data, + }); + } + + /** + * Construct an Approve instruction + * + * @param account Public key of the account + * @param delegate Account authorized to perform a transfer of tokens from the source account + * @param owner Owner of the source account + * @param multiSigners Signing accounts if `owner` is a multiSig + * @param amount Maximum number of tokens the delegate may transfer + */ + static createRevokeInstruction( + programId: PublicKey, + account: PublicKey, + owner: any, + multiSigners: Array, + ): TransactionInstruction { + const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]); + + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 5, // Approve instruction + }, + data, + ); + + let keys = [{pubkey: account, isSigner: false, isWritable: true}]; + if (isAccount(owner)) { + keys.push({pubkey: owner.publicKey, isSigner: true, isWritable: false}); + } else { + keys.push({pubkey: owner, isSigner: false, isWritable: false}); + multiSigners.forEach(signer => + keys.push({ + pubkey: signer.publicKey, + isSigner: true, + isWritable: false, + }), + ); + } + + return new TransactionInstruction({ + keys, + programId: programId, + data, + }); + } + + /** + * Construct a SetOwner instruction + * + * @param account Public key of the account + * @param newOwner New owner of the account + * @param owner Owner of the account + * @param multiSigners Signing accounts if `owner` is a multiSig + */ + static createSetOwnerInstruction( + programId: PublicKey, + owned: PublicKey, + newOwner: PublicKey, + owner: any, + multiSigners: Array, + ): TransactionInstruction { + const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]); + + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 6, // SetOwner instruction + }, + data, + ); + + let keys = [ + {pubkey: owned, isSigner: false, isWritable: true}, + {pubkey: newOwner, isSigner: false, isWritable: false}, + ]; + if (isAccount(owner)) { + keys.push({pubkey: owner.publicKey, isSigner: true, isWritable: false}); + } else { + keys.push({pubkey: owner, isSigner: false, isWritable: false}); + multiSigners.forEach(signer => + keys.push({ + pubkey: signer.publicKey, + isSigner: true, + isWritable: false, + }), + ); + } + + return new TransactionInstruction({ + keys, + programId: programId, + data, + }); + } + + /** + * Construct a MintTo instruction + * + * @param dest Public key of the account to mint to + * @param authority Owner of the mint + * @param multiSigners Signing accounts if `authority` is a multiSig + + * @param amount amount to mint + */ + static createMintToInstruction( + programId: PublicKey, + mint: PublicKey, + dest: PublicKey, + authority: any, + multiSigners: Array, + amount: number, + ): TransactionInstruction { + const dataLayout = BufferLayout.struct([ + BufferLayout.u8('instruction'), + Layout.uint64('amount'), + ]); + + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 7, // MintTo instruction + amount: new u64(amount).toBuffer(), + }, + data, + ); + + let keys = [ + {pubkey: mint, isSigner: false, isWritable: true}, + {pubkey: dest, isSigner: false, isWritable: true}, + ]; + if (isAccount(authority)) { + keys.push({ + pubkey: authority.publicKey, + isSigner: true, + isWritable: false, + }); + } else { + keys.push({pubkey: authority, isSigner: false, isWritable: false}); + multiSigners.forEach(signer => + keys.push({ + pubkey: signer.publicKey, + isSigner: true, + isWritable: false, + }), + ); + } + + return new TransactionInstruction({ + keys, + programId: programId, + data, + }); + } + + /** + * Construct a Burn instruction + * + * @param account Account to burn tokens from + * @param authority Public key account owner + * @param multiSigners Signing accounts if `authority` is a multiSig + * @param amount ammount to burn + */ + static createBurnInstruction( + programId: PublicKey, + account: PublicKey, + authority: any, + multiSigners: Array, + amount: number, + ): TransactionInstruction { + const dataLayout = BufferLayout.struct([ + BufferLayout.u8('instruction'), + Layout.uint64('amount'), + ]); + + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 8, // Burn instruction + amount: new u64(amount).toBuffer(), + }, + data, + ); + + let keys = [{pubkey: account, isSigner: false, isWritable: true}]; + if (isAccount(authority)) { + keys.push({ + pubkey: authority.publicKey, + isSigner: true, + isWritable: false, + }); + } else { + keys.push({pubkey: authority, isSigner: false, isWritable: false}); + multiSigners.forEach(signer => + keys.push({ + pubkey: signer.publicKey, + isSigner: true, + isWritable: false, + }), + ); + } + + return new TransactionInstruction({ + keys, + programId: programId, + data, + }); + } + + /** + * Construct a Burn instruction + * + * @param account Account to burn tokens from + * @param owner account owner + * @param multiSigners Signing accounts if `owner` is a multiSig + */ + static createCloseAccountInstruction( + programId: PublicKey, + account: PublicKey, + dest: PublicKey, + owner: any, + multiSigners: Array, + ): TransactionInstruction { + const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]); + const data = Buffer.alloc(dataLayout.span); + dataLayout.encode( + { + instruction: 9, // CloseAccount instruction + }, + data, + ); + + let keys = [ + {pubkey: account, isSigner: false, isWritable: true}, + {pubkey: dest, isSigner: false, isWritable: true}, + ]; + if (isAccount(owner)) { + keys.push({pubkey: owner.publicKey, isSigner: true, isWritable: false}); + } else { + keys.push({pubkey: owner, isSigner: false, isWritable: false}); + multiSigners.forEach(signer => + keys.push({ + pubkey: signer.publicKey, + isSigner: true, + isWritable: false, + }), + ); + } + + return new TransactionInstruction({ + keys, + programId: programId, + data, + }); + } +} diff --git a/program/js/client/util/new-account-with-lamports.js b/program/js/client/util/new-account-with-lamports.js new file mode 100644 index 0000000..423972f --- /dev/null +++ b/program/js/client/util/new-account-with-lamports.js @@ -0,0 +1,25 @@ +// @flow + +import {Account, Connection} from '@solana/web3.js'; + +import {sleep} from './sleep'; + +export async function newAccountWithLamports( + connection: Connection, + lamports: number = 1000000, +): Promise { + const account = new Account(); + + let retries = 30; + await connection.requestAirdrop(account.publicKey, lamports); + for (;;) { + await sleep(500); + if (lamports == (await connection.getBalance(account.publicKey))) { + return account; + } + if (--retries <= 0) { + break; + } + } + throw new Error(`Airdrop of ${lamports} failed`); +} diff --git a/program/js/client/util/new-system-account-with-airdrop.js b/program/js/client/util/new-system-account-with-airdrop.js new file mode 100644 index 0000000..2df5779 --- /dev/null +++ b/program/js/client/util/new-system-account-with-airdrop.js @@ -0,0 +1,17 @@ +// @flow + +import {Account, Connection} from '@solana/web3.js'; + +/** + * Create a new system account and airdrop it some lamports + * + * @private + */ +export async function newSystemAccountWithAirdrop( + connection: Connection, + lamports: number = 1, +): Promise { + const account = new Account(); + await connection.requestAirdrop(account.publicKey, lamports); + return account; +} diff --git a/program/js/client/util/send-and-confirm-transaction.js b/program/js/client/util/send-and-confirm-transaction.js new file mode 100644 index 0000000..1088c55 --- /dev/null +++ b/program/js/client/util/send-and-confirm-transaction.js @@ -0,0 +1,21 @@ +// @flow + +import {sendAndConfirmTransaction as realSendAndConfirmTransaction} from '@solana/web3.js'; +import type { + Account, + Connection, + Transaction, + TransactionSignature, +} from '@solana/web3.js'; + +export function sendAndConfirmTransaction( + title: string, + connection: Connection, + transaction: Transaction, + ...signers: Array +): Promise { + return realSendAndConfirmTransaction(connection, transaction, signers, { + confirmations: 1, + skipPreflight: true, + }); +} diff --git a/program/js/client/util/sleep.js b/program/js/client/util/sleep.js new file mode 100644 index 0000000..961d48c --- /dev/null +++ b/program/js/client/util/sleep.js @@ -0,0 +1,6 @@ +// @flow + +// zzz +export function sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/program/js/client/util/store.js b/program/js/client/util/store.js new file mode 100644 index 0000000..fdafb9d --- /dev/null +++ b/program/js/client/util/store.js @@ -0,0 +1,26 @@ +/** + * Simple file-based datastore + * + * @flow + */ + +import path from 'path'; +import fs from 'mz/fs'; +import mkdirp from 'mkdirp-promise'; + +export class Store { + dir = path.join(__dirname, 'store'); + + async load(uri: string): Promise { + const filename = path.join(this.dir, uri); + const data = await fs.readFile(filename, 'utf8'); + const config = JSON.parse(data); + return config; + } + + async save(uri: string, config: Object): Promise { + await mkdirp(this.dir); + const filename = path.join(this.dir, uri); + await fs.writeFile(filename, JSON.stringify(config), 'utf8'); + } +} diff --git a/program/js/cluster-devnet.env b/program/js/cluster-devnet.env new file mode 100644 index 0000000..eccad41 --- /dev/null +++ b/program/js/cluster-devnet.env @@ -0,0 +1,2 @@ +LIVE=1 +CLUSTER=devnet diff --git a/program/js/cluster-mainnet-beta.env b/program/js/cluster-mainnet-beta.env new file mode 100644 index 0000000..17239e5 --- /dev/null +++ b/program/js/cluster-mainnet-beta.env @@ -0,0 +1,2 @@ +LIVE=1 +CLUSTER=mainnet-beta diff --git a/program/js/cluster-testnet.env b/program/js/cluster-testnet.env new file mode 100644 index 0000000..9bcfb25 --- /dev/null +++ b/program/js/cluster-testnet.env @@ -0,0 +1,2 @@ +LIVE=1 +CLUSTER=testnet diff --git a/program/js/flow-typed/bn.js.js b/program/js/flow-typed/bn.js.js new file mode 100644 index 0000000..5412142 --- /dev/null +++ b/program/js/flow-typed/bn.js.js @@ -0,0 +1,4 @@ +declare module 'bn.js' { + // TODO: Fill in types + declare module.exports: any; +} diff --git a/program/js/flow-typed/bs58.js b/program/js/flow-typed/bs58.js new file mode 100644 index 0000000..9223fad --- /dev/null +++ b/program/js/flow-typed/bs58.js @@ -0,0 +1,6 @@ +declare module 'bs58' { + declare module.exports: { + encode(input: Buffer): string; + decode(input: string): Buffer; + }; +} diff --git a/program/js/flow-typed/buffer-layout.js b/program/js/flow-typed/buffer-layout.js new file mode 100644 index 0000000..9dd66fe --- /dev/null +++ b/program/js/flow-typed/buffer-layout.js @@ -0,0 +1,4 @@ +declare module 'buffer-layout' { + // TODO: Fill in types + declare module.exports: any; +} diff --git a/program/js/flow-typed/mkdirp-promise_vx.x.x.js b/program/js/flow-typed/mkdirp-promise_vx.x.x.js new file mode 100644 index 0000000..35bb720 --- /dev/null +++ b/program/js/flow-typed/mkdirp-promise_vx.x.x.js @@ -0,0 +1,32 @@ +// flow-typed signature: 65e18196703cbb222ea294226e99826d +// flow-typed version: <>/mkdirp-promise_v5.0.1/flow_v0.84.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'mkdirp-promise' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'mkdirp-promise' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'mkdirp-promise/lib/index' { + declare module.exports: any; +} + +// Filename aliases +declare module 'mkdirp-promise/lib/index.js' { + declare module.exports: $Exports<'mkdirp-promise/lib/index'>; +} diff --git a/program/js/flow-typed/npm/mz_vx.x.x.js b/program/js/flow-typed/npm/mz_vx.x.x.js new file mode 100644 index 0000000..b4b12f4 --- /dev/null +++ b/program/js/flow-typed/npm/mz_vx.x.x.js @@ -0,0 +1,73 @@ +// flow-typed signature: ed29f42bf4f4916e4f3ba1f5e7343c9d +// flow-typed version: <>/mz_v2.7.0/flow_v0.81.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'mz' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'mz' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'mz/child_process' { + declare module.exports: any; +} + +declare module 'mz/crypto' { + declare module.exports: any; +} + +declare module 'mz/dns' { + declare module.exports: any; +} + +declare module 'mz/fs' { + declare module.exports: any; +} + +declare module 'mz/readline' { + declare module.exports: any; +} + +declare module 'mz/zlib' { + declare module.exports: any; +} + +// Filename aliases +declare module 'mz/child_process.js' { + declare module.exports: $Exports<'mz/child_process'>; +} +declare module 'mz/crypto.js' { + declare module.exports: $Exports<'mz/crypto'>; +} +declare module 'mz/dns.js' { + declare module.exports: $Exports<'mz/dns'>; +} +declare module 'mz/fs.js' { + declare module.exports: $Exports<'mz/fs'>; +} +declare module 'mz/index' { + declare module.exports: $Exports<'mz'>; +} +declare module 'mz/index.js' { + declare module.exports: $Exports<'mz'>; +} +declare module 'mz/readline.js' { + declare module.exports: $Exports<'mz/readline'>; +} +declare module 'mz/zlib.js' { + declare module.exports: $Exports<'mz/zlib'>; +} diff --git a/program/js/flow-typed/semver.js b/program/js/flow-typed/semver.js new file mode 100644 index 0000000..3d6c800 --- /dev/null +++ b/program/js/flow-typed/semver.js @@ -0,0 +1,3 @@ +declare module 'semver' { + declare module.exports: any; +} diff --git a/program/js/module.d.ts b/program/js/module.d.ts new file mode 100644 index 0000000..4295bad --- /dev/null +++ b/program/js/module.d.ts @@ -0,0 +1,160 @@ +declare module '@solana/spl-token' { + import {Buffer} from 'buffer'; + import { PublicKey, TransactionInstruction, TransactionSignature, Connection } from "@solana/web3.js"; + import BN from 'bn.js'; + + // === client/token.js === + export class u64 extends BN { + toBuffer(): Buffer; + static fromBuffer(buffer: Buffer): u64; + } + export type MintInfo = { + owner: null | PublicKey, + decimals: number, + initialized: boolean, + }; + export type AccountInfo = { + mint: PublicKey, + owner: PublicKey, + amount: u64, + delegate: null | PublicKey, + delegatedAmount: u64, + isInitialized: boolean, + isNative: boolean, + }; + export type MultisigInfo = { + m: number, + n: number, + initialized: boolean, + signer1: PublicKey, + signer2: PublicKey, + signer3: PublicKey, + signer4: PublicKey, + signer5: PublicKey, + signer6: PublicKey, + signer7: PublicKey, + signer8: PublicKey, + signer9: PublicKey, + signer10: PublicKey, + signer11: PublicKey, + }; + export type TokenAndPublicKey = [Token, PublicKey]; + export class Token { + constructor( + connection: Connection, + publicKey: PublicKey, + programId: PublicKey, + payer: Account, + ); + static createMint( + connection: Connection, + payer: Account, + mintOwner: PublicKey, + accountOwner: PublicKey, + supply: u64, + decimals: number, + programId: PublicKey, + is_owned: boolean, + ): Promise; + static getAccount(connection: Connection): Promise; + createAccount(owner: PublicKey): Promise; + createMultisig(m: number, signers: Array): Promise; + getMintInfo(): Promise; + getAccountInfo(account: PublicKey): Promise; + getMultisigInfo(multisig: PublicKey): Promise; + transfer( + source: PublicKey, + destination: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number | u64, + ): Promise; + approve( + account: PublicKey, + delegate: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + amount: number | u64, + ): Promise; + revoke( + account: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): Promise; + setOwner( + owned: PublicKey, + newOwner: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): Promise; + mintTo( + dest: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number, + ): Promise; + burn( + account: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number, + ): Promise; + closeAccount( + account: PublicKey, + dest: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): Promise; + static createTransferInstruction( + programId: PublicKey, + source: PublicKey, + destination: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number | u64, + ): TransactionInstruction; + static createApproveInstruction( + programId: PublicKey, + account: PublicKey, + delegate: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + amount: number | u64, + ): TransactionInstruction; + static createRevokeInstruction( + programId: PublicKey, + account: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): TransactionInstruction; + static createSetOwnerInstruction( + programId: PublicKey, + owned: PublicKey, + newOwner: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): TransactionInstruction; + static createMintToInstruction( + programId: PublicKey, + mint: PublicKey, + dest: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number, + ): TransactionInstruction; + static createBurnInstruction( + programId: PublicKey, + account: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number, + ): TransactionInstruction; + static createCloseAccountInstruction( + programId: PublicKey, + account: PublicKey, + dest: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): TransactionInstruction; + } +} diff --git a/program/js/module.flow.js b/program/js/module.flow.js new file mode 100644 index 0000000..1d81229 --- /dev/null +++ b/program/js/module.flow.js @@ -0,0 +1,163 @@ +/** + * Flow Library definition for spl-token + * + * This file is manually maintained + * + */ + +declare module '@solana/spl-token' { + // === client/token.js === + declare export class u64 extends BN { + toBuffer(): Buffer; + static fromBuffer(buffer: Buffer): u64; + } + declare export type MintInfo = {| + owner: null | PublicKey, + decimals: number, + initialized: boolean, + |}; + declare export type AccountInfo = {| + mint: PublicKey, + owner: PublicKey, + amount: u64, + delegate: null | PublicKey, + delegatedAmount: u64, + isInitialized: boolean, + isNative: boolean, + |}; + declare export type MultisigInfo = {| + m: number, + n: number, + initialized: boolean, + signer1: PublicKey, + signer2: PublicKey, + signer3: PublicKey, + signer4: PublicKey, + signer5: PublicKey, + signer6: PublicKey, + signer7: PublicKey, + signer8: PublicKey, + signer9: PublicKey, + signer10: PublicKey, + signer11: PublicKey, + |}; + declare export type TokenAndPublicKey = [Token, PublicKey]; + declare export class Token { + constructor( + connection: Connection, + publicKey: PublicKey, + programId: PublicKey, + payer: Account, + ): Token; + static createMint( + connection: Connection, + payer: Account, + mintOwner: PublicKey, + accountOwner: PublicKey, + supply: u64, + decimals: number, + programId: PublicKey, + is_owned: boolean, + ): Promise; + static getAccount(connection: Connection): Promise; + createAccount(owner: PublicKey): Promise; + createMultisig(m: number, signers: Array): Promise; + getMintInfo(): Promise; + getAccountInfo(account: PublicKey): Promise; + getMultisigInfo(multisig: PublicKey): Promise; + transfer( + source: PublicKey, + destination: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number | u64, + ): Promise; + approve( + account: PublicKey, + delegate: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + amount: number | u64, + ): Promise; + revoke( + account: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): Promise; + setOwner( + owned: PublicKey, + newOwner: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): Promise; + mintTo( + dest: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number, + ): Promise; + burn( + account: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number, + ): Promise; + closeAccount( + account: PublicKey, + dest: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): Promise; + static createTransferInstruction( + programId: PublicKey, + source: PublicKey, + destination: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number | u64, + ): TransactionInstruction; + static createApproveInstruction( + programId: PublicKey, + account: PublicKey, + delegate: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + amount: number | u64, + ): TransactionInstruction; + static createRevokeInstruction( + programId: PublicKey, + account: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): TransactionInstruction; + static createSetOwnerInstruction( + programId: PublicKey, + owned: PublicKey, + newOwner: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): TransactionInstruction; + static createMintToInstruction( + programId: PublicKey, + mint: PublicKey, + dest: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number, + ): TransactionInstruction; + static createBurnInstruction( + programId: PublicKey, + account: PublicKey, + authority: Account | PublicKey, + multiSigners: Array, + amount: number, + ): TransactionInstruction; + static createCloseAccountInstruction( + programId: PublicKey, + account: PublicKey, + dest: PublicKey, + owner: Account | PublicKey, + multiSigners: Array, + ): TransactionInstructio; + } +} diff --git a/program/js/package-lock.json b/program/js/package-lock.json new file mode 100644 index 0000000..91be906 --- /dev/null +++ b/program/js/package-lock.json @@ -0,0 +1,8383 @@ +{ + "name": "@solana/spl-token", + "version": "0.0.5", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "101": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/101/-/101-1.6.3.tgz", + "integrity": "sha512-4dmQ45yY0Dx24Qxp+zAsNLlMF6tteCyfVzgbulvSyC7tCyd3V8sW76sS0tHq8NpcbXfWTKasfyfzU1Kd86oKzw==", + "requires": { + "clone": "^1.0.2", + "deep-eql": "^0.1.3", + "keypather": "^1.10.2" + } + }, + "@babel/cli": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.10.5.tgz", + "integrity": "sha512-j9H9qSf3kLdM0Ao3aGPbGZ73mEA9XazuupcS6cDGWuiyAcANoguhP0r2Lx32H5JGw4sSSoHG3x/mxVnHgvOoyA==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "commander": "^4.0.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/compat-data": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz", + "integrity": "sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/core": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz", + "integrity": "sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-module-transforms": "^7.11.0", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.11.1", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.11.0", + "@babel/types": "^7.11.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/generator": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", + "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.1.tgz", + "integrity": "sha512-u9QMIRdKVF7hfEkb3nu2LgZDIzCQPv+yHD9Eg6ruoJLjkrQ9fFz4IBSlF/9XwoNri9+2F1IY+dYuOfZrXq8t3w==", + "dev": true + }, + "@babel/traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", + "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.0", + "@babel/types": "^7.11.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.5.tgz", + "integrity": "sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig==", + "dev": true, + "requires": { + "@babel/types": "^7.10.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", + "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.10.4", + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", + "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.10.5", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", + "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^7.10.4", + "regexpu-core": "^4.7.0" + } + }, + "@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz", + "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==", + "dev": true, + "requires": { + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.5.tgz", + "integrity": "sha512-HiqJpYD5+WopCXIAbQDG0zye5XYVvcO9w/DHp5GsaGkRUaamLj2bEtu6i8rnGGprAhHM3qidCMgp71HF4endhA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.5" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@babel/helper-module-transforms": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.5.tgz", + "integrity": "sha512-4P+CWMJ6/j1W915ITJaUkadLObmCRRSC234uctJfn/vHrsLNxsR8dwlcXv9ZhJWzl77awf+mWXSZEKt5t0OnlA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", + "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/types": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz", + "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/generator": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.5.tgz", + "integrity": "sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig==", + "dev": true, + "requires": { + "@babel/types": "^7.10.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", + "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.5.tgz", + "integrity": "sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.5", + "@babel/types": "^7.10.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@babel/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", + "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", + "dev": true + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/types": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz", + "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + }, + "dependencies": { + "@babel/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", + "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/node": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/node/-/node-7.10.5.tgz", + "integrity": "sha512-suosS7zZ2roj+fYVCnDuVezUbRc0sdoyF0Gj/1FzWxD4ebbGiBGtL5qyqHH4NO34B5m4vWWYWgyNhSsrqS8vwA==", + "dev": true, + "requires": { + "@babel/register": "^7.10.5", + "commander": "^4.0.1", + "core-js": "^3.2.1", + "lodash": "^4.17.19", + "node-environment-flags": "^1.0.5", + "regenerator-runtime": "^0.13.4", + "resolve": "^1.13.1", + "v8flags": "^3.1.1" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "@babel/parser": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", + "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", + "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", + "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", + "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz", + "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", + "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz", + "integrity": "sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", + "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", + "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", + "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", + "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz", + "integrity": "sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", + "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", + "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", + "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.10.4.tgz", + "integrity": "sha512-yxQsX1dJixF4qEEdzVbst3SZQ58Nrooz8NV9Z9GL4byTE25BvJgl5lf0RECUf0fh28rZBb/RYTWn/eeKwCMrZQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", + "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", + "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", + "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", + "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz", + "integrity": "sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", + "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", + "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", + "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", + "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", + "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", + "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.10.4.tgz", + "integrity": "sha512-XTadyuqNst88UWBTdLjM+wEY7BFnY2sYtPyAidfC7M/QaZnSuIZpMvLxqGT7phAcnGyWh/XQFLKcGf04CnvxSQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-flow": "^7.10.4" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", + "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", + "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", + "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", + "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", + "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", + "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", + "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", + "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", + "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", + "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", + "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", + "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", + "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", + "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", + "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz", + "integrity": "sha512-LFEsP+t3wkYBlis8w6/kmnd6Kb1dxTd+wGJ8MlxTGzQo//ehtqlVL4S9DNUa53+dtPSQobN2CXx4d81FqC58cw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", + "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz", + "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", + "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^7.10.4" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", + "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", + "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", + "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", + "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/preset-env": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.0.tgz", + "integrity": "sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.11.0", + "@babel/helper-compilation-targets": "^7.10.4", + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-proposal-async-generator-functions": "^7.10.4", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-dynamic-import": "^7.10.4", + "@babel/plugin-proposal-export-namespace-from": "^7.10.4", + "@babel/plugin-proposal-json-strings": "^7.10.4", + "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", + "@babel/plugin-proposal-numeric-separator": "^7.10.4", + "@babel/plugin-proposal-object-rest-spread": "^7.11.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", + "@babel/plugin-proposal-optional-chaining": "^7.11.0", + "@babel/plugin-proposal-private-methods": "^7.10.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.10.4", + "@babel/plugin-transform-arrow-functions": "^7.10.4", + "@babel/plugin-transform-async-to-generator": "^7.10.4", + "@babel/plugin-transform-block-scoped-functions": "^7.10.4", + "@babel/plugin-transform-block-scoping": "^7.10.4", + "@babel/plugin-transform-classes": "^7.10.4", + "@babel/plugin-transform-computed-properties": "^7.10.4", + "@babel/plugin-transform-destructuring": "^7.10.4", + "@babel/plugin-transform-dotall-regex": "^7.10.4", + "@babel/plugin-transform-duplicate-keys": "^7.10.4", + "@babel/plugin-transform-exponentiation-operator": "^7.10.4", + "@babel/plugin-transform-for-of": "^7.10.4", + "@babel/plugin-transform-function-name": "^7.10.4", + "@babel/plugin-transform-literals": "^7.10.4", + "@babel/plugin-transform-member-expression-literals": "^7.10.4", + "@babel/plugin-transform-modules-amd": "^7.10.4", + "@babel/plugin-transform-modules-commonjs": "^7.10.4", + "@babel/plugin-transform-modules-systemjs": "^7.10.4", + "@babel/plugin-transform-modules-umd": "^7.10.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", + "@babel/plugin-transform-new-target": "^7.10.4", + "@babel/plugin-transform-object-super": "^7.10.4", + "@babel/plugin-transform-parameters": "^7.10.4", + "@babel/plugin-transform-property-literals": "^7.10.4", + "@babel/plugin-transform-regenerator": "^7.10.4", + "@babel/plugin-transform-reserved-words": "^7.10.4", + "@babel/plugin-transform-shorthand-properties": "^7.10.4", + "@babel/plugin-transform-spread": "^7.11.0", + "@babel/plugin-transform-sticky-regex": "^7.10.4", + "@babel/plugin-transform-template-literals": "^7.10.4", + "@babel/plugin-transform-typeof-symbol": "^7.10.4", + "@babel/plugin-transform-unicode-escapes": "^7.10.4", + "@babel/plugin-transform-unicode-regex": "^7.10.4", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.11.0", + "browserslist": "^4.12.0", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + }, + "dependencies": { + "@babel/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/preset-flow": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.10.4.tgz", + "integrity": "sha512-XI6l1CptQCOBv+ZKYwynyswhtOKwpZZp5n0LG1QKCo8erRhqjoQV6nvx61Eg30JHpysWQSBwA2AWRU3pBbSY5g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-transform-flow-strip-types": "^7.10.4" + } + }, + "@babel/preset-modules": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz", + "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/register": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.10.5.tgz", + "integrity": "sha512-eYHdLv43nyvmPn9bfNfrcC4+iYNwdQ8Pxk1MFJuU/U5LpSYl/PH4dFMazCYZDFVi8ueG3shvO+AQfLrxpYulQw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "pirates": "^4.0.0", + "source-map-support": "^0.5.16" + } + }, + "@babel/runtime": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", + "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "requires": { + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + } + } + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + } + } + }, + "@babel/traverse": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.5.tgz", + "integrity": "sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.5", + "@babel/types": "^7.10.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@octokit/auth-token": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.2.tgz", + "integrity": "sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ==", + "dev": true, + "requires": { + "@octokit/types": "^5.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.5.tgz", + "integrity": "sha512-70K5u6zd45ItOny6aHQAsea8HHQjlQq85yqOMe+Aj8dkhN2qSJ9T+Q3YjUjEYfPRBcuUWNgMn62DQnP/4LAIiQ==", + "dev": true, + "requires": { + "@octokit/types": "^5.0.0", + "is-plain-object": "^4.0.0", + "universal-user-agent": "^6.0.0" + }, + "dependencies": { + "is-plain-object": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz", + "integrity": "sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA==", + "dev": true + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + } + } + }, + "@octokit/plugin-paginate-rest": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", + "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", + "dev": true, + "requires": { + "@octokit/types": "^2.0.1" + }, + "dependencies": { + "@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "dev": true, + "requires": { + "@types/node": ">= 8" + } + } + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz", + "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==", + "dev": true + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", + "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", + "dev": true, + "requires": { + "@octokit/types": "^2.0.1", + "deprecation": "^2.3.1" + }, + "dependencies": { + "@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "dev": true, + "requires": { + "@types/node": ">= 8" + } + } + } + }, + "@octokit/request": { + "version": "5.4.7", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.7.tgz", + "integrity": "sha512-FN22xUDP0i0uF38YMbOfx6TotpcENP5W8yJM1e/LieGXn6IoRxDMnBf7tx5RKSW4xuUZ/1P04NFZy5iY3Rax1A==", + "dev": true, + "requires": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.0.0", + "@octokit/types": "^5.0.0", + "deprecation": "^2.0.0", + "is-plain-object": "^4.0.0", + "node-fetch": "^2.3.0", + "once": "^1.4.0", + "universal-user-agent": "^6.0.0" + }, + "dependencies": { + "@octokit/request-error": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.2.tgz", + "integrity": "sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw==", + "dev": true, + "requires": { + "@octokit/types": "^5.0.1", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "is-plain-object": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz", + "integrity": "sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA==", + "dev": true + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + } + } + }, + "@octokit/request-error": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz", + "integrity": "sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==", + "dev": true, + "requires": { + "@octokit/types": "^2.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "dependencies": { + "@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "dev": true, + "requires": { + "@types/node": ">= 8" + } + } + } + }, + "@octokit/rest": { + "version": "16.43.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", + "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", + "dev": true, + "requires": { + "@octokit/auth-token": "^2.4.0", + "@octokit/plugin-paginate-rest": "^1.1.1", + "@octokit/plugin-request-log": "^1.0.0", + "@octokit/plugin-rest-endpoint-methods": "2.4.0", + "@octokit/request": "^5.2.0", + "@octokit/request-error": "^1.0.2", + "atob-lite": "^2.0.0", + "before-after-hook": "^2.0.0", + "btoa-lite": "^1.0.0", + "deprecation": "^2.0.0", + "lodash.get": "^4.4.2", + "lodash.set": "^4.3.2", + "lodash.uniq": "^4.5.0", + "octokit-pagination-methods": "^1.1.0", + "once": "^1.4.0", + "universal-user-agent": "^4.0.0" + } + }, + "@octokit/types": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.2.0.tgz", + "integrity": "sha512-XjOk9y4m8xTLIKPe1NFxNWBdzA2/z3PFFA/bwf4EoH6oS8hM0Y46mEa4Cb+KCyj/tFDznJFahzQ0Aj3o1FYq4A==", + "dev": true, + "requires": { + "@types/node": ">= 8" + } + }, + "@rollup/plugin-babel": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.1.0.tgz", + "integrity": "sha512-zXBEYmfiLAMvB+ZBa6m/q9hsQYAq1sUFdjuP1F6C2pf6uQcpHwAWQveZgzS63zXdKPUYHD3Dr7BhjCqcr0bbLw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.7.4", + "@rollup/pluginutils": "^3.0.8" + } + }, + "@rollup/plugin-commonjs": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz", + "integrity": "sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8", + "commondir": "^1.0.1", + "estree-walker": "^1.0.1", + "glob": "^7.1.2", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@sindresorhus/is": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", + "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==", + "dev": true + }, + "@solana/web3.js": { + "version": "0.64.0", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-0.64.0.tgz", + "integrity": "sha512-DlNzAXgNdk7k4Pt6CfcaAutaiXJiog9hxswtzItf0q/0/Um8JvDI1YjnMONE3IKI/jyjmTaxhsQHWAQE42KofQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "bn.js": "^5.0.0", + "bs58": "^4.0.1", + "buffer": "^5.4.3", + "buffer-layout": "^1.2.0", + "crypto-hash": "^1.2.2", + "esdoc-inject-style-plugin": "^1.0.0", + "jayson": "^3.0.1", + "mz": "^2.7.0", + "node-fetch": "^2.2.0", + "npm-run-all": "^4.1.5", + "rpc-websockets": "^5.0.8", + "superstruct": "^0.8.3", + "tweetnacl": "^1.0.0", + "ws": "^7.0.0" + } + }, + "@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "requires": { + "@types/node": "*" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/express-serve-static-core": { + "version": "4.17.9", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz", + "integrity": "sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/fs-extra": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.1.tgz", + "integrity": "sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/lodash": { + "version": "4.14.158", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.158.tgz", + "integrity": "sha512-InCEXJNTv/59yO4VSfuvNrZHt7eeNtWQEgnieIA+mIC+MOWM9arOWG2eQ8Vhk6NbOre6/BidiXhkZYeDY9U35w==" + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "10.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.6.tgz", + "integrity": "sha512-Fvm24+u85lGmV4hT5G++aht2C5I4Z4dYlWZIh62FAfFO/TfzXtPpoLI6I7AuBWkIFqZCnhFOoTT7RjjaIL5Fjg==" + }, + "@types/qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==" + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "acorn": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "optional": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "optional": true + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "assert-args": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/assert-args/-/assert-args-1.2.1.tgz", + "integrity": "sha1-QEEDoUUqMv53iYgR5U5ZCoqTc70=", + "requires": { + "101": "^1.2.0", + "compound-subject": "0.0.1", + "debug": "^2.2.0", + "get-prototype-of": "0.0.0", + "is-capitalized": "^1.0.0", + "is-class": "0.0.4" + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "optional": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true, + "optional": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "optional": true + }, + "atob-lite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", + "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=", + "dev": true + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "optional": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "before-after-hook": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", + "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", + "dev": true + }, + "big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", + "dev": true + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "dev": true, + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", + "dev": true + }, + "bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==" + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "optional": true + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browserslist": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.13.0.tgz", + "integrity": "sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001093", + "electron-to-chromium": "^1.3.488", + "escalade": "^3.0.1", + "node-releases": "^1.1.58" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "requires": { + "base-x": "^3.0.2" + } + }, + "btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", + "dev": true + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-indexof-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz", + "integrity": "sha1-qfuAbOgUXVQoUQznLyeLs2OmOL8=", + "dev": true + }, + "buffer-layout": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.0.tgz", + "integrity": "sha512-iiyRoho/ERzBUv6kFvfsrLNgTlVwOkqQcSQN7WrO3Y+c5SeuEhCn6+y1KwhM0V3ndptF5mI/RI44zkw0qcR5Jg==" + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "optional": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-lookup": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", + "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", + "dev": true, + "requires": { + "@types/keyv": "^3.1.1", + "keyv": "^4.0.0" + } + }, + "cacheable-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001109", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001109.tgz", + "integrity": "sha512-4JIXRodHzdS3HdK8nSgIqXYLExOvG+D2/EenSvcub2Kp3QEADjo2v2oUn5g0n0D+UNwG9BtwKOyGcSq2qvQXvQ==", + "dev": true + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "dev": true, + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "dev": true + }, + "cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash.assignin": "^4.0.9", + "lodash.bind": "^4.1.4", + "lodash.defaults": "^4.0.1", + "lodash.filter": "^4.4.0", + "lodash.flatten": "^4.2.0", + "lodash.foreach": "^4.3.0", + "lodash.map": "^4.4.0", + "lodash.merge": "^4.4.0", + "lodash.pick": "^4.2.1", + "lodash.reduce": "^4.4.0", + "lodash.reject": "^4.4.0", + "lodash.some": "^4.4.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "optional": true + }, + "circular-json": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", + "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==" + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "optional": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + }, + "dependencies": { + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "optional": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true, + "optional": true + }, + "compound-subject": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/compound-subject/-/compound-subject-0.0.1.tgz", + "integrity": "sha1-JxVUaYoVrmCLHfyv0wt7oeqJLEs=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "optional": true + }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, + "core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "requires": { + "browserslist": "^4.8.5", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "dev": true + }, + "crypto-hash": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.2.2.tgz", + "integrity": "sha512-rXXMXepuKg9gIfqE7I1jtVa6saLhzIkDQ2u3kTGUWYiUGsHcUa3LTsfrjPEdOY8kxKlryQtsOmJOU0F23yRJTg==" + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "optional": true + }, + "decompress-response": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", + "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", + "dev": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "requires": { + "type-detect": "0.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "defer-to-connect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", + "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + }, + "dependencies": { + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + } + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.514", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.514.tgz", + "integrity": "sha512-8vb8zKIeGlZigeDzNWWthmGeLzo5CC43Lc+CZshMs7UXFVMPNLtXJGa/txedpu3OJFrXXVheBwp9PqOJJlHQ8w==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escalade": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", + "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esdoc-inject-style-plugin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esdoc-inject-style-plugin/-/esdoc-inject-style-plugin-1.0.0.tgz", + "integrity": "sha1-oTWXNou5+4nDZeBmSVyvl6Tey7E=", + "requires": { + "cheerio": "0.22.0", + "fs-extra": "1.0.0" + } + }, + "eslint": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.6.0.tgz", + "integrity": "sha512-QlAManNtqr7sozWm5TF4wIH9gmUm2hE3vNRUvyoYAa4y1l5/jxD/PQStEjBMQtCqZmSep8UxrcecI60hOpe61w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.2.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", + "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-scope": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", + "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz", + "integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==", + "dev": true, + "requires": { + "acorn": "^7.3.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, + "exec-sh": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", + "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", + "dev": true, + "requires": { + "merge": "^1.2.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "optional": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "optional": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "flow-bin": { + "version": "0.131.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.131.0.tgz", + "integrity": "sha512-fZmoIBcDrtLhy/NNMxwJysSYzMr1ksRcAOMi3AHSoYXfcuQqTvhGJx+wqjlIOqIwz8RRYm8J4V4JrSJbIKP+Xg==", + "dev": true + }, + "flow-typed": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/flow-typed/-/flow-typed-3.2.1.tgz", + "integrity": "sha512-vWQLZmndgdEHdy1TKTeI1DkLLa4078p6vhcKz/IZ6fcpaWLElTSG7rZi3BxlcSWfEQPxsymuSBNwAT7dCpXm6g==", + "dev": true, + "requires": { + "@octokit/rest": "^16.43.1", + "colors": "^1.4.0", + "flowgen": "^1.10.0", + "fs-extra": "^8.1.0", + "glob": "^7.1.6", + "got": "^10.5.7", + "md5": "^2.2.1", + "mkdirp": "^1.0.3", + "prettier": "^1.19.1", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "table": "^5.4.6", + "through": "^2.3.8", + "unzipper": "^0.10.8", + "which": "^2.0.2", + "yargs": "^15.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "flowgen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/flowgen/-/flowgen-1.11.0.tgz", + "integrity": "sha512-WpoBjzcZadnAw5FatlUbvFWUWXkI2/LjrwTl5fl3MVDh+KdvYgFzgRXDDKH/O2uUlwjfpveiJJJx8TwL7Se84A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/highlight": "^7.9.0", + "commander": "^5.1.0", + "lodash": "^4.17.15", + "prettier": "^2.0.5", + "shelljs": "^0.8.4", + "typescript": "^3.4", + "typescript-compiler": "^1.4.1-2" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "optional": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "optional": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + }, + "dependencies": { + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "^4.1.6" + } + } + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true, + "optional": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz", + "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", + "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", + "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true, + "optional": true + } + } + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-prototype-of": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/get-prototype-of/-/get-prototype-of-0.0.0.tgz", + "integrity": "sha1-mHcr0QcW0W3rSzIlFsRp78oorEQ=" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "optional": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "got": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", + "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", + "dev": true, + "requires": { + "@sindresorhus/is": "^2.0.0", + "@szmarczak/http-timer": "^4.0.0", + "@types/cacheable-request": "^6.0.1", + "cacheable-lookup": "^2.0.0", + "cacheable-request": "^7.0.1", + "decompress-response": "^5.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^5.0.0", + "lowercase-keys": "^2.0.0", + "mimic-response": "^2.1.0", + "p-cancelable": "^2.0.0", + "p-event": "^4.0.0", + "responselike": "^2.0.0", + "to-readable-stream": "^2.0.0", + "type-fest": "^0.10.0" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "type-fest": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", + "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "optional": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" + }, + "is-capitalized": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-capitalized/-/is-capitalized-1.0.0.tgz", + "integrity": "sha1-TIRktNkdPk7rRIid0s2PGwrEwTY=" + }, + "is-class": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/is-class/-/is-class-0.0.4.tgz", + "integrity": "sha1-4FdFFwW7NOOePjNZjJOpg3KWtzY=" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "optional": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "optional": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "optional": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "requires": { + "has-symbols": "^1.0.1" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + } + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "optional": true + }, + "jayson": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-3.3.3.tgz", + "integrity": "sha512-0bQ/vNvWyi+fzNoMvRK63m7BGU+PWwaJRVaGgJWZeAL5euOSqJtqzqyCrfiS3Sdw3OrvgKWF5f5N8ut87gxrng==", + "requires": { + "@types/connect": "^3.4.32", + "@types/express-serve-static-core": "^4.16.9", + "@types/lodash": "^4.14.139", + "@types/node": "^12.7.7", + "JSONStream": "^1.3.1", + "commander": "^2.12.2", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "uuid": "^3.2.1" + }, + "dependencies": { + "@types/node": { + "version": "12.12.53", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.53.tgz", + "integrity": "sha512-51MYTDTyCziHb70wtGNFRwB4l+5JNvdqzFSkbDvpbftEgVUBEE+T5f7pROhWMp/fxp07oNIEQZd5bbfAH22ohQ==" + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "keypather": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/keypather/-/keypather-1.10.2.tgz", + "integrity": "sha1-4ESWMtSz5RbyHMAUznxWRP3c5hQ=", + "requires": { + "101": "^1.0.0" + } + }, + "keyv": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.1.tgz", + "integrity": "sha512-xz6Jv6oNkbhrFCvCP7HQa8AaII8y8LRpoSm661NOKLr4uHuBwhX4epXrPQgF3+xdJnN4Esm5X0xwY4bOlALOtw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + }, + "lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=" + }, + "lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" + }, + "lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" + }, + "lodash.reject": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=" + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", + "dev": true + }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "macos-release": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.4.1.tgz", + "integrity": "sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg==", + "dev": true + }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "optional": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "optional": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", + "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", + "dev": true, + "requires": { + "charenc": "~0.0.1", + "crypt": "~0.0.1", + "is-buffer": "~1.1.1" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" + }, + "merge": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", + "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "optional": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "optional": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "optional": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "optional": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "optional": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "optional": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "optional": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=", + "requires": { + "mkdirp": "*" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "optional": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "optional": true + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-releases": { + "version": "1.1.60", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", + "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "optional": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "optional": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "optional": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "octokit-pagination-methods": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", + "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-name": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "dev": true, + "requires": { + "macos-release": "^2.2.0", + "windows-release": "^3.1.0" + } + }, + "p-cancelable": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", + "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==", + "dev": true + }, + "p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "requires": { + "p-timeout": "^3.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "optional": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true, + "optional": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "optional": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "optional": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "optional": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "optional": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "optional": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "regenerate": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", + "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "regexpu-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true, + "optional": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "optional": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "optional": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", + "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true, + "optional": true + }, + "responselike": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "optional": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.23.1.tgz", + "integrity": "sha512-Heyl885+lyN/giQwxA8AYT2GY3U+gOlTqVLrMQYno8Z1X9lAOpfXPiKiZCyPc25e9BLJM3Zlh957dpTlO4pa8A==", + "dev": true, + "requires": { + "fsevents": "~2.1.2" + }, + "dependencies": { + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + } + } + }, + "rollup-plugin-copy": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.3.0.tgz", + "integrity": "sha512-euDjCUSBXZa06nqnwCNADbkAcYDfzwowfZQkto9K/TFhiH+QG7I4PUsEMwM9tDgomGWJc//z7KLW8t+tZwxADA==", + "dev": true, + "requires": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true + } + } + }, + "rpc-websockets": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-5.2.4.tgz", + "integrity": "sha512-6jqeJK/18hPTsmeiN+K9O4miZiAmrIncgxfPXHwuGWs9BClA2zC3fOnTThRWo4blkrjH59oKKi0KMxSK+wdtNw==", + "requires": { + "@babel/runtime": "^7.8.7", + "assert-args": "^1.2.1", + "babel-runtime": "^6.26.0", + "circular-json": "^0.5.9", + "eventemitter3": "^3.1.2", + "uuid": "^3.4.0", + "ws": "^5.2.2" + }, + "dependencies": { + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "optional": true, + "requires": { + "ret": "~0.1.10" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" + }, + "shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "optional": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "optional": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "optional": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "optional": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true, + "optional": true + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "optional": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "optional": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "string.prototype.padend": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz", + "integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "superstruct": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.8.4.tgz", + "integrity": "sha512-48Ors8IVWZm/tMr8r0Si6+mJiB7mkD7jqvIzktjJ4+EnP5tBp0qOpiM1J8sCUorKx+TXWrfb3i1UcjdD1YK/wA==", + "requires": { + "kind-of": "^6.0.2", + "tiny-invariant": "^1.0.6" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + } + } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "through": { + "version": "2.3.8", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", + "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==", + "dev": true + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "optional": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "dev": true + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "typescript-compiler": { + "version": "1.4.1-2", + "resolved": "https://registry.npmjs.org/typescript-compiler/-/typescript-compiler-1.4.1-2.tgz", + "integrity": "sha1-uk99si2RU0oZKdkACdzhYety/T8=", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "optional": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "universal-user-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz", + "integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==", + "dev": true, + "requires": { + "os-name": "^3.1.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "optional": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "optional": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "optional": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "optional": true + } + } + }, + "unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "requires": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "optional": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true, + "optional": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "watch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", + "integrity": "sha1-NApxe952Vyb6CqB9ch4BR6VR3ww=", + "dev": true, + "requires": { + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "windows-release": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.1.tgz", + "integrity": "sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A==", + "dev": true, + "requires": { + "execa": "^1.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", + "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "optional": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/program/js/package.json b/program/js/package.json new file mode 100644 index 0000000..4016239 --- /dev/null +++ b/program/js/package.json @@ -0,0 +1,78 @@ +{ + "name": "@solana/spl-token", + "version": "0.0.5", + "description": "SPL Token Javascript API", + "license": "MIT", + "author": "Solana Maintainers ", + "homepage": "https://solana.com/", + "repository": { + "type": "git", + "url": "https://github.com/solana-labs/solana-program-library" + }, + "bugs": { + "url": "https://github.com/solana-labs/solana-program-library/issues" + }, + "publishConfig": { + "access": "public" + }, + "main": "lib/index.cjs.js", + "module": "lib/index.esm.js", + "types": "lib/index.d.ts", + "files": [ + "/lib", + "/module.flow.js" + ], + "testnetDefaultChannel": "v1.3.1", + "scripts": { + "build": "rollup -c", + "start": "babel-node cli/main.js", + "lint": "npm run pretty && eslint .", + "lint:fix": "npm run lint -- --fix", + "flow": "flow", + "flow:watch": "watch 'flow' . --wait=1 --ignoreDirectoryPattern=/doc/", + "lint:watch": "watch 'npm run lint:fix' . --wait=1", + "build:program": "rm client/util/store/config.json; ../../do.sh build token", + "cluster:localnet": "rm -f .env", + "cluster:devnet": "cp cluster-devnet.env .env", + "cluster:testnet": "cp cluster-testnet.env .env", + "cluster:mainnet-beta": "cp cluster-mainnet-beta.env .env", + "localnet:update": "solana-localnet update", + "localnet:up": "rm client/util/store/config.json; set -x; solana-localnet down; set -e; solana-localnet up", + "localnet:down": "solana-localnet down", + "localnet:logs": "solana-localnet logs -f", + "pretty": "prettier --write '{,cli*/**/}*.js'" + }, + "dependencies": { + "@babel/runtime": "^7.10.5", + "@solana/web3.js": "^0.64.0", + "bn.js": "^5.0.0", + "buffer-layout": "^1.2.0", + "dotenv": "8.2.0", + "mkdirp-promise": "^5.0.1" + }, + "devDependencies": { + "@babel/cli": "^7.10.5", + "@babel/core": "^7.10.5", + "@babel/node": "^7.10.5", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-transform-runtime": "^7.10.5", + "@babel/preset-env": "^7.10.4", + "@babel/preset-flow": "^7.10.4", + "@rollup/plugin-babel": "^5.1.0", + "@rollup/plugin-commonjs": "^14.0.0", + "babel-eslint": "^10.1.0", + "eslint": "^7.4.0", + "eslint-plugin-import": "^2.22.0", + "flow-bin": "0.131.0", + "flow-typed": "^3.2.0", + "mz": "^2.7.0", + "prettier": "^2.0.5", + "rollup": "^2.23.0", + "rollup-plugin-copy": "^3.3.0", + "semver": "^7.0.0", + "watch": "^1.0.2" + }, + "engines": { + "node": ">= 10" + } +} diff --git a/program/js/rollup.config.js b/program/js/rollup.config.js new file mode 100644 index 0000000..211e4b7 --- /dev/null +++ b/program/js/rollup.config.js @@ -0,0 +1,74 @@ +import babel from '@rollup/plugin-babel'; +import commonjs from '@rollup/plugin-commonjs'; +import copy from 'rollup-plugin-copy'; + +function generateConfig(configType) { + const config = { + input: 'client/token.js', + plugins: [ + babel({ + configFile: './babel.rollup.config.json', + exclude: 'node_modules/**', + babelHelpers: 'runtime', + }), + commonjs(), + copy({ + targets: [{src: 'module.d.ts', dest: 'lib', rename: 'index.d.ts'}], + }), + ], + }; + + switch (configType) { + case 'browser': + // TODO: Add support + break; + case 'node': + config.output = [ + { + file: 'lib/index.cjs.js', + format: 'cjs', + sourcemap: true, + }, + { + file: 'lib/index.esm.js', + format: 'es', + sourcemap: true, + }, + ]; + + // Quash 'Unresolved dependencies' complaints for modules listed in the + // package.json "dependencies" section. Unfortunately this list is manually + // maintained. + config.external = [ + 'assert', + '@babel/runtime/core-js/get-iterator', + '@babel/runtime/core-js/json/stringify', + '@babel/runtime/core-js/object/assign', + '@babel/runtime/core-js/object/get-prototype-of', + '@babel/runtime/core-js/object/keys', + '@babel/runtime/core-js/promise', + '@babel/runtime/helpers/asyncToGenerator', + '@babel/runtime/helpers/classCallCheck', + '@babel/runtime/helpers/createClass', + '@babel/runtime/helpers/defineProperty', + '@babel/runtime/helpers/get', + '@babel/runtime/helpers/getPrototypeOf', + '@babel/runtime/helpers/inherits', + '@babel/runtime/helpers/possibleConstructorReturn', + '@babel/runtime/helpers/slicedToArray', + '@babel/runtime/helpers/toConsumableArray', + '@babel/runtime/helpers/typeof', + '@babel/runtime/regenerator', + 'bn.js', + 'buffer-layout', + '@solana/web3.js', + ]; + break; + default: + throw new Error(`Unknown configType: ${configType}`); + } + + return config; +} + +export default [generateConfig('node')]; diff --git a/program/js/url.js b/program/js/url.js new file mode 100644 index 0000000..3138a7c --- /dev/null +++ b/program/js/url.js @@ -0,0 +1,31 @@ +// To connect to a public cluster, set `export LIVE=1` in your +// environment. By default, `LIVE=1` will connect to the devnet cluster. + +import {clusterApiUrl, Cluster} from '@solana/web3.js'; +import dotenv from 'dotenv'; + +function chooseCluster(): Cluster | undefined { + dotenv.config(); + if (!process.env.LIVE) return; + switch (process.env.CLUSTER) { + case 'devnet': + case 'testnet': + case 'mainnet-beta': { + return process.env.CLUSTER; + } + } + throw 'Unknown cluster "' + process.env.CLUSTER + '", check the .env file'; +} + +export const cluster = chooseCluster(); + +export const url = + process.env.RPC_URL || + (process.env.LIVE ? clusterApiUrl(cluster, false) : 'http://localhost:8899'); + +export const urlTls = + process.env.RPC_URL || + (process.env.LIVE ? clusterApiUrl(cluster, true) : 'http://localhost:8899'); + +export let walletUrl = + process.env.WALLET_URL || 'https://solana-example-webwallet.herokuapp.com/'; diff --git a/program/program-id.md b/program/program-id.md new file mode 100644 index 0000000..77df2a0 --- /dev/null +++ b/program/program-id.md @@ -0,0 +1 @@ +TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs new file mode 100644 index 0000000..b5594ca --- /dev/null +++ b/program/src/entrypoint.rs @@ -0,0 +1,24 @@ +//! Program entrypoint + +#![cfg(feature = "program")] +#![cfg(not(feature = "no-entrypoint"))] + +use crate::{error::TokenError, processor::Processor}; +use solana_sdk::{ + account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, + program_error::PrintProgramError, pubkey::Pubkey, +}; + +entrypoint!(process_instruction); +fn process_instruction<'a>( + program_id: &Pubkey, + accounts: &'a [AccountInfo<'a>], + instruction_data: &[u8], +) -> ProgramResult { + if let Err(error) = Processor::process(program_id, accounts, instruction_data) { + // catch the error so we can print it + error.print::(); + return Err(error); + } + Ok(()) +} diff --git a/program/src/error.rs b/program/src/error.rs new file mode 100644 index 0000000..32f9822 --- /dev/null +++ b/program/src/error.rs @@ -0,0 +1,56 @@ +//! Error types + +use num_derive::FromPrimitive; +use solana_sdk::{decode_error::DecodeError, program_error::ProgramError}; +use thiserror::Error; + +/// Errors that may be returned by the Token program. +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] +pub enum TokenError { + /// Insufficient funds for the operation requested. + #[error("Insufficient funds")] + InsufficientFunds, + /// Account not associated with this Mint. + #[error("Account not associated with this Mint")] + MintMismatch, + /// Owner does not match. + #[error("Owner does not match")] + OwnerMismatch, + /// This token's supply is fixed and new tokens cannot be minted. + #[error("Fixed supply")] + FixedSupply, + /// The account cannot be initialized because it is already being used. + #[error("AlreadyInUse")] + AlreadyInUse, + /// An owner is required if initial supply is zero. + #[error("An owner is required if supply is zero")] + OwnerRequiredIfNoInitialSupply, + /// Invalid number of provided signers. + #[error("Invalid number of provided signers")] + InvalidNumberOfProvidedSigners, + /// Invalid number of required signers. + #[error("Invalid number of required signers")] + InvalidNumberOfRequiredSigners, + /// State is uninitialized. + #[error("State is unititialized")] + UninitializedState, + /// Instruction does not support native tokens + #[error("Instruction does not support native tokens")] + NativeNotSupported, + /// Instruction does not support non-native tokens + #[error("Instruction does not support non-native tokens")] + NonNativeNotSupported, + /// Invalid instruction + #[error("Invalid instruction")] + InvalidInstruction, +} +impl From for ProgramError { + fn from(e: TokenError) -> Self { + ProgramError::Custom(e as u32) + } +} +impl DecodeError for TokenError { + fn type_of() -> &'static str { + "TokenError" + } +} diff --git a/program/src/instruction.rs b/program/src/instruction.rs new file mode 100644 index 0000000..e3e78e7 --- /dev/null +++ b/program/src/instruction.rs @@ -0,0 +1,593 @@ +//! Instruction types + +use crate::error::TokenError; +use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + pubkey::Pubkey, +}; +use std::mem::size_of; + +/// Minimum number of multisignature signers (min N) +pub const MIN_SIGNERS: usize = 1; +/// Maximum number of multisignature signers (max N) +pub const MAX_SIGNERS: usize = 11; + +/// Instructions supported by the token program. +#[repr(C)] +#[derive(Clone, Debug, PartialEq)] +pub enum TokenInstruction { + /// Initializes a new mint and optionally deposits all the newly minted tokens in an account. + /// + /// The `InitializeMint` instruction requires no signers and MUST be included within + /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The mint to initialize. + /// 1. + /// * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. + /// * If supply is zero: `[]` The owner/multisignature of the mint. + /// 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if + /// present then further minting is supported. + /// + InitializeMint { + /// Initial amount of tokens to mint. + amount: u64, + /// Number of base 10 digits to the right of the decimal place. + decimals: u8, + }, + /// Initializes a new account to hold tokens. If this account is associated with the native mint + /// then the token balance of the initialized account will be equal to the amount of SOL in the account. + /// + /// The `InitializeAccount` instruction requires no signers and MUST be included within + /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// 1. `[]` The mint this account will be associated with. + /// 2. `[]` The new account's owner/multisignature. + InitializeAccount, + /// Initializes a multisignature account with N provided signers. + /// + /// Multisignature accounts can used in place of any single owner/delegate accounts in any + /// token instruction that require an owner/delegate to be present. The variant field represents the + /// number of signers (M) required to validate this multisignature account. + /// + /// The `InitializeMultisig` instruction requires no signers and MUST be included within + /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The multisignature account to initialize. + /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + InitializeMultisig { + /// The number of signers (M) required to validate this multisignature account. + m: u8, + }, + /// Transfers tokens from one account to another either directly or via a delegate. If this + /// account is associated with the native mint then equal amounts of SOL and Tokens will be + /// transferred to the destination account. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The source account. + /// 1. `[writable]` The destination account. + /// 2. '[signer]' The source account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The source account. + /// 1. `[writable]` The destination account. + /// 2. '[]' The source account's multisignature owner/delegate. + /// 3. ..3+M '[signer]' M signer accounts. + Transfer { + /// The amount of tokens to transfer. + amount: u64, + }, + /// Approves a delegate. A delegate is given the authority over + /// tokens on behalf of the source account's owner. + + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The source account. + /// 1. `[]` The delegate. + /// 2. `[signer]` The source account owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The source account. + /// 1. `[]` The delegate. + /// 2. '[]' The source account's multisignature owner. + /// 3. ..3+M '[signer]' M signer accounts + Approve { + /// The amount of tokens the delegate is approved for. + amount: u64, + }, + /// Revokes the delegate's authority. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The source account. + /// 1. `[signer]` The source account owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The source account. + /// 1. '[]' The source account's multisignature owner. + /// 2. ..2+M '[signer]' M signer accounts + Revoke, + /// Sets a new owner of a mint or account. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The mint or account to change the owner of. + /// 1. `[]` The new owner/delegate/multisignature. + /// 2. `[signer]` The owner of the mint or account. + /// + /// * Multisignature owner + /// 0. `[writable]` The mint or account to change the owner of. + /// 1. `[]` The new owner/delegate/multisignature. + /// 2. `[]` The mint's or account's multisignature owner. + /// 3. ..3+M '[signer]' M signer accounts + SetOwner, + /// Mints new tokens to an account. The native mint does not support minting. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[signer]` The mint's owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[]` The mint's multisignature owner. + /// 3. ..3+M '[signer]' M signer accounts. + MintTo { + /// The amount of new tokens to mint. + amount: u64, + }, + /// Burns tokens by removing them from an account. `Burn` does not support accounts + /// associated with the native mint, use `CloseAccount` instead. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. `[signer]` The account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. `[]` The account's multisignature owner/delegate. + /// 2. ..2+M '[signer]' M signer accounts. + Burn { + /// The amount of tokens to burn. + amount: u64, + }, + /// Close an account by transferring all its SOL to the destination account. + /// Non-native accounts may only be closed if its token amount is zero. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The account to close. + /// 1. '[writable]' The destination account. + /// 2. `[signer]` The account's owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The account to close. + /// 1. '[writable]' The destination account. + /// 2. `[]` The account's multisignature owner. + /// 3. ..3+M '[signer]' M signer accounts. + CloseAccount, +} +impl TokenInstruction { + /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). + pub fn unpack(input: &[u8]) -> Result { + if input.len() < size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + Ok(match input[0] { + 0 => { + if input.len() < size_of::() + size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + let decimals = + unsafe { *(&input[size_of::() + size_of::()] as *const u8) }; + Self::InitializeMint { amount, decimals } + } + 1 => Self::InitializeAccount, + 2 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let m = unsafe { *(&input[1] as *const u8) }; + Self::InitializeMultisig { m } + } + 3 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + Self::Transfer { amount } + } + 4 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + Self::Approve { amount } + } + 5 => Self::Revoke, + 6 => Self::SetOwner, + 7 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + Self::MintTo { amount } + } + 8 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + Self::Burn { amount } + } + 9 => Self::CloseAccount, + _ => return Err(TokenError::InvalidInstruction.into()), + }) + } + + /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. + pub fn pack(self: &Self) -> Result, ProgramError> { + let mut output = vec![0u8; size_of::()]; + match self { + Self::InitializeMint { amount, decimals } => { + output[0] = 0; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + *value = *amount; + let value = + unsafe { &mut *(&mut output[size_of::() + size_of::()] as *mut u8) }; + *value = *decimals; + } + Self::InitializeAccount => output[0] = 1, + Self::InitializeMultisig { m } => { + output[0] = 2; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u8) }; + *value = *m; + } + Self::Transfer { amount } => { + output[0] = 3; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + *value = *amount; + } + Self::Approve { amount } => { + output[0] = 4; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + *value = *amount; + } + Self::Revoke => output[0] = 5, + Self::SetOwner => output[0] = 6, + Self::MintTo { amount } => { + output[0] = 7; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + *value = *amount; + } + Self::Burn { amount } => { + output[0] = 8; + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + *value = *amount; + } + Self::CloseAccount => output[0] = 9, + } + Ok(output) + } +} + +/// Creates a 'InitializeMint' instruction. +pub fn initialize_mint( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, + account_pubkey: Option<&Pubkey>, + owner_pubkey: Option<&Pubkey>, + amount: u64, + decimals: u8, +) -> Result { + let data = TokenInstruction::InitializeMint { amount, decimals }.pack()?; + + let mut accounts = vec![AccountMeta::new(*mint_pubkey, false)]; + if amount != 0 { + match account_pubkey { + Some(pubkey) => accounts.push(AccountMeta::new(*pubkey, false)), + None => { + return Err(ProgramError::NotEnoughAccountKeys); + } + } + } + match owner_pubkey { + Some(pubkey) => accounts.push(AccountMeta::new_readonly(*pubkey, false)), + None => { + if amount == 0 { + return Err(TokenError::OwnerRequiredIfNoInitialSupply.into()); + } + } + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `InitializeAccount` instruction. +pub fn initialize_account( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + owner_pubkey: &Pubkey, +) -> Result { + let data = TokenInstruction::InitializeAccount.pack()?; + + let accounts = vec![ + AccountMeta::new(*account_pubkey, false), + AccountMeta::new_readonly(*mint_pubkey, false), + AccountMeta::new_readonly(*owner_pubkey, false), + ]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `InitializeMultisig` instruction. +pub fn initialize_multisig( + token_program_id: &Pubkey, + multisig_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + m: u8, +) -> Result { + if !is_valid_signer_index(m as usize) + || !is_valid_signer_index(signer_pubkeys.len()) + || m as usize > signer_pubkeys.len() + { + return Err(ProgramError::MissingRequiredSignature); + } + let data = TokenInstruction::InitializeMultisig { m }.pack()?; + + let mut accounts = Vec::with_capacity(1 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*multisig_pubkey, false)); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `Transfer` instruction. +pub fn transfer( + token_program_id: &Pubkey, + source_pubkey: &Pubkey, + destination_pubkey: &Pubkey, + authority_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, +) -> Result { + let data = TokenInstruction::Transfer { amount }.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*source_pubkey, false)); + accounts.push(AccountMeta::new(*destination_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *authority_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates an `Approve` instruction. +pub fn approve( + token_program_id: &Pubkey, + source_pubkey: &Pubkey, + delegate_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, +) -> Result { + let data = TokenInstruction::Approve { amount }.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*source_pubkey, false)); + accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `Revoke` instruction. +pub fn revoke( + token_program_id: &Pubkey, + source_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], +) -> Result { + let data = TokenInstruction::Revoke.pack()?; + + let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); + accounts.push(AccountMeta::new_readonly(*source_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `SetOwner` instruction. +pub fn set_owner( + token_program_id: &Pubkey, + owned_pubkey: &Pubkey, + new_owner_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], +) -> Result { + let data = TokenInstruction::SetOwner.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*owned_pubkey, false)); + accounts.push(AccountMeta::new_readonly(*new_owner_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `MintTo` instruction. +pub fn mint_to( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, + account_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, +) -> Result { + let data = TokenInstruction::MintTo { amount }.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*mint_pubkey, false)); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `Burn` instruction. +pub fn burn( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + authority_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, +) -> Result { + let data = TokenInstruction::Burn { amount }.pack()?; + + let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *authority_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `CloseAccount` instruction. +pub fn close_account( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + destination_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], +) -> Result { + let data = TokenInstruction::CloseAccount.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new(*destination_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS +pub fn is_valid_signer_index(index: usize) -> bool { + !(index < MIN_SIGNERS || index > MAX_SIGNERS) +} diff --git a/program/src/lib.rs b/program/src/lib.rs new file mode 100644 index 0000000..bc39c05 --- /dev/null +++ b/program/src/lib.rs @@ -0,0 +1,28 @@ +#![deny(missing_docs)] + +//! An ERC20-like Token program for the Solana blockchain + +pub mod entrypoint; +pub mod error; +pub mod instruction; +pub mod native_mint; +pub mod option; +pub mod processor; +pub mod state; + +// Export current solana-sdk types for downstream users who may also be building with a different +// solana-sdk version +pub use solana_sdk; + +/// Convert the UI representation of a token amount (using the decimals field defined in its mint) +/// to the raw amount +pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { + (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 +} + +/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { + amount as f64 / 10_usize.pow(decimals as u32) as f64 +} + +solana_sdk::declare_id!("TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"); diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs new file mode 100644 index 0000000..6e80b28 --- /dev/null +++ b/program/src/native_mint.rs @@ -0,0 +1,25 @@ +//! The Mint that represents the native token + +/// There are 10^9 lamports in one SOL +pub const DECIMALS: u8 = 9; + +// The Mint for native SOL Token accounts +solana_sdk::declare_id!("So11111111111111111111111111111111111111111"); + +#[cfg(test)] +mod tests { + use super::*; + use solana_sdk::native_token::*; + + #[test] + fn test_decimals() { + assert_eq!( + lamports_to_sol(42), + crate::amount_to_ui_amount(42, DECIMALS) + ); + assert_eq!( + sol_to_lamports(42.), + crate::ui_amount_to_amount(42., DECIMALS) + ); + } +} diff --git a/program/src/option.rs b/program/src/option.rs new file mode 100644 index 0000000..914bb51 --- /dev/null +++ b/program/src/option.rs @@ -0,0 +1,965 @@ +//! A C representation of Rust's `std::option::Option` used accross the FFI +//! boundary for Solana program interfaces +//! +//! This implementation mostly matches `std::option` except iterators since the iteration +//! trait requires returning `std::option::Option` + +use std::pin::Pin; +use std::{ + convert, hint, mem, + ops::{Deref, DerefMut}, +}; + +/// A C representation of Rust's `std::option::Option` +#[repr(C)] +#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +pub enum COption { + /// No value + None, + /// Some value `T` + Some(T), +} + +///////////////////////////////////////////////////////////////////////////// +// Type implementation +///////////////////////////////////////////////////////////////////////////// + +impl COption { + ///////////////////////////////////////////////////////////////////////// + // Querying the contained values + ///////////////////////////////////////////////////////////////////////// + + /// Returns `true` if the option is a [`COption::Some`] value. + /// + /// # Examples + /// + /// ```ignore + /// let x: COption = COption::Some(2); + /// assert_eq!(x.is_some(), true); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.is_some(), false); + /// ``` + /// + /// [`COption::Some`]: #variant.COption::Some + #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] + #[inline] + pub fn is_some(&self) -> bool { + match *self { + COption::Some(_) => true, + COption::None => false, + } + } + + /// Returns `true` if the option is a [`COption::None`] value. + /// + /// # Examples + /// + /// ```ignore + /// let x: COption = COption::Some(2); + /// assert_eq!(x.is_none(), false); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.is_none(), true); + /// ``` + /// + /// [`COption::None`]: #variant.COption::None + #[must_use = "if you intended to assert that this doesn't have a value, consider \ + `.and_then(|| panic!(\"`COption` had a value when expected `COption::None`\"))` instead"] + #[inline] + pub fn is_none(&self) -> bool { + !self.is_some() + } + + /// Returns `true` if the option is a [`COption::Some`] value containing the given value. + /// + /// # Examples + /// + /// ```ignore + /// #![feature(option_result_contains)] + /// + /// let x: COption = COption::Some(2); + /// assert_eq!(x.contains(&2), true); + /// + /// let x: COption = COption::Some(3); + /// assert_eq!(x.contains(&2), false); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.contains(&2), false); + /// ``` + #[must_use] + #[inline] + pub fn contains(&self, x: &U) -> bool + where + U: PartialEq, + { + match self { + COption::Some(y) => x == y, + COption::None => false, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Adapter for working with references + ///////////////////////////////////////////////////////////////////////// + + /// Converts from `&COption` to `COption<&T>`. + /// + /// # Examples + /// + /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, preserving the original. + /// The [`map`] method takes the `self` argument by value, consuming the original, + /// so this technique uses `as_ref` to first take an `COption` to a reference + /// to the value inside the original. + /// + /// [`map`]: enum.COption.html#method.map + /// [`String`]: ../../std/string/struct.String.html + /// [`usize`]: ../../std/primitive.usize.html + /// + /// ```ignore + /// let text: COption = COption::Some("Hello, world!".to_string()); + /// // First, cast `COption` to `COption<&String>` with `as_ref`, + /// // then consume *that* with `map`, leaving `text` on the stack. + /// let text_length: COption = text.as_ref().map(|s| s.len()); + /// println!("still can print text: {:?}", text); + /// ``` + #[inline] + pub fn as_ref(&self) -> COption<&T> { + match *self { + COption::Some(ref x) => COption::Some(x), + COption::None => COption::None, + } + } + + /// Converts from `&mut COption` to `COption<&mut T>`. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::Some(2); + /// match x.as_mut() { + /// COption::Some(v) => *v = 42, + /// COption::None => {}, + /// } + /// assert_eq!(x, COption::Some(42)); + /// ``` + #[inline] + pub fn as_mut(&mut self) -> COption<&mut T> { + match *self { + COption::Some(ref mut x) => COption::Some(x), + COption::None => COption::None, + } + } + + /// Converts from [`Pin`]`<&COption>` to `COption<`[`Pin`]`<&T>>`. + /// + /// [`Pin`]: ../pin/struct.Pin.html + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn as_pin_ref(self: Pin<&Self>) -> COption> { + unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } + } + + /// Converts from [`Pin`]`<&mut COption>` to `COption<`[`Pin`]`<&mut T>>`. + /// + /// [`Pin`]: ../pin/struct.Pin.html + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn as_pin_mut(self: Pin<&mut Self>) -> COption> { + unsafe { + Pin::get_unchecked_mut(self) + .as_mut() + .map(|x| Pin::new_unchecked(x)) + } + } + + ///////////////////////////////////////////////////////////////////////// + // Getting to contained values + ///////////////////////////////////////////////////////////////////////// + + /// Unwraps an option, yielding the content of a [`COption::Some`]. + /// + /// # Panics + /// + /// Panics if the value is a [`COption::None`] with a custom panic message provided by + /// `msg`. + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("value"); + /// assert_eq!(x.expect("the world is ending"), "value"); + /// ``` + /// + /// ```ignore{.should_panic} + /// let x: COption<&str> = COption::None; + /// x.expect("the world is ending"); // panics with `the world is ending` + /// ``` + #[inline] + pub fn expect(self, msg: &str) -> T { + match self { + COption::Some(val) => val, + COption::None => expect_failed(msg), + } + } + + /// Moves the value `v` out of the `COption` if it is [`COption::Some(v)`]. + /// + /// In general, because this function may panic, its use is discouraged. + /// Instead, prefer to use pattern matching and handle the [`COption::None`] + /// case explicitly. + /// + /// # Panics + /// + /// Panics if the self value equals [`COption::None`]. + /// + /// [`COption::Some(v)`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("air"); + /// assert_eq!(x.unwrap(), "air"); + /// ``` + /// + /// ```ignore{.should_panic} + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.unwrap(), "air"); // fails + /// ``` + #[inline] + pub fn unwrap(self) -> T { + match self { + COption::Some(val) => val, + COption::None => panic!("called `COption::unwrap()` on a `COption::None` value"), + } + } + + /// Returns the contained value or a default. + /// + /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use [`unwrap_or_else`], + /// which is lazily evaluated. + /// + /// [`unwrap_or_else`]: #method.unwrap_or_else + /// + /// # Examples + /// + /// ```ignore + /// assert_eq!(COption::Some("car").unwrap_or("bike"), "car"); + /// assert_eq!(COption::None.unwrap_or("bike"), "bike"); + /// ``` + #[inline] + pub fn unwrap_or(self, def: T) -> T { + match self { + COption::Some(x) => x, + COption::None => def, + } + } + + /// Returns the contained value or computes it from a closure. + /// + /// # Examples + /// + /// ```ignore + /// let k = 10; + /// assert_eq!(COption::Some(4).unwrap_or_else(|| 2 * k), 4); + /// assert_eq!(COption::None.unwrap_or_else(|| 2 * k), 20); + /// ``` + #[inline] + pub fn unwrap_or_else T>(self, f: F) -> T { + match self { + COption::Some(x) => x, + COption::None => f(), + } + } + + ///////////////////////////////////////////////////////////////////////// + // Transforming contained values + ///////////////////////////////////////////////////////////////////////// + + /// Maps an `COption` to `COption` by applying a function to a contained value. + /// + /// # Examples + /// + /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, consuming the original: + /// + /// [`String`]: ../../std/string/struct.String.html + /// [`usize`]: ../../std/primitive.usize.html + /// + /// ```ignore + /// let maybe_some_string = COption::Some(String::from("Hello, World!")); + /// // `COption::map` takes self *by value*, consuming `maybe_some_string` + /// let maybe_some_len = maybe_some_string.map(|s| s.len()); + /// + /// assert_eq!(maybe_some_len, COption::Some(13)); + /// ``` + #[inline] + pub fn map U>(self, f: F) -> COption { + match self { + COption::Some(x) => COption::Some(f(x)), + COption::None => COption::None, + } + } + + /// Applies a function to the contained value (if any), + /// or returns the provided default (if not). + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.map_or(42, |v| v.len()), 3); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.map_or(42, |v| v.len()), 42); + /// ``` + #[inline] + pub fn map_or U>(self, default: U, f: F) -> U { + match self { + COption::Some(t) => f(t), + COption::None => default, + } + } + + /// Applies a function to the contained value (if any), + /// or computes a default (if not). + /// + /// # Examples + /// + /// ```ignore + /// let k = 21; + /// + /// let x = COption::Some("foo"); + /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42); + /// ``` + #[inline] + pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { + match self { + COption::Some(t) => f(t), + COption::None => default(), + } + } + + /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to + /// [`Ok(v)`] and [`COption::None`] to [`Err(err)`]. + /// + /// Arguments passed to `ok_or` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`ok_or_else`], which is + /// lazily evaluated. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Err(err)`]: ../../std/result/enum.Result.html#variant.Err + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(v)`]: #variant.COption::Some + /// [`ok_or_else`]: #method.ok_or_else + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.ok_or(0), Ok("foo")); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.ok_or(0), Err(0)); + /// ``` + #[inline] + pub fn ok_or(self, err: E) -> Result { + match self { + COption::Some(v) => Ok(v), + COption::None => Err(err), + } + } + + /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to + /// [`Ok(v)`] and [`COption::None`] to [`Err(err())`]. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Err(err())`]: ../../std/result/enum.Result.html#variant.Err + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(v)`]: #variant.COption::Some + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.ok_or_else(|| 0), Ok("foo")); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.ok_or_else(|| 0), Err(0)); + /// ``` + #[inline] + pub fn ok_or_else E>(self, err: F) -> Result { + match self { + COption::Some(v) => Ok(v), + COption::None => Err(err()), + } + } + + ///////////////////////////////////////////////////////////////////////// + // Boolean operations on the values, eager and lazy + ///////////////////////////////////////////////////////////////////////// + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise returns `optb`. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y: COption<&str> = COption::None; + /// assert_eq!(x.and(y), COption::None); + /// + /// let x: COption = COption::None; + /// let y = COption::Some("foo"); + /// assert_eq!(x.and(y), COption::None); + /// + /// let x = COption::Some(2); + /// let y = COption::Some("foo"); + /// assert_eq!(x.and(y), COption::Some("foo")); + /// + /// let x: COption = COption::None; + /// let y: COption<&str> = COption::None; + /// assert_eq!(x.and(y), COption::None); + /// ``` + #[inline] + pub fn and(self, optb: COption) -> COption { + match self { + COption::Some(_) => optb, + COption::None => COption::None, + } + } + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `f` with the + /// wrapped value and returns the result. + /// + /// COption::Some languages call this operation flatmap. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// fn sq(x: u32) -> COption { COption::Some(x * x) } + /// fn nope(_: u32) -> COption { COption::None } + /// + /// assert_eq!(COption::Some(2).and_then(sq).and_then(sq), COption::Some(16)); + /// assert_eq!(COption::Some(2).and_then(sq).and_then(nope), COption::None); + /// assert_eq!(COption::Some(2).and_then(nope).and_then(sq), COption::None); + /// assert_eq!(COption::None.and_then(sq).and_then(sq), COption::None); + /// ``` + #[inline] + pub fn and_then COption>(self, f: F) -> COption { + match self { + COption::Some(x) => f(x), + COption::None => COption::None, + } + } + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `predicate` + /// with the wrapped value and returns: + /// + /// - [`COption::Some(t)`] if `predicate` returns `true` (where `t` is the wrapped + /// value), and + /// - [`COption::None`] if `predicate` returns `false`. + /// + /// This function works similar to [`Iterator::filter()`]. You can imagine + /// the `COption` being an iterator over one or zero elements. `filter()` + /// lets you decide which elements to keep. + /// + /// # Examples + /// + /// ```ignore + /// fn is_even(n: &i32) -> bool { + /// n % 2 == 0 + /// } + /// + /// assert_eq!(COption::None.filter(is_even), COption::None); + /// assert_eq!(COption::Some(3).filter(is_even), COption::None); + /// assert_eq!(COption::Some(4).filter(is_even), COption::Some(4)); + /// ``` + /// + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(t)`]: #variant.COption::Some + /// [`Iterator::filter()`]: ../../std/iter/trait.Iterator.html#method.filter + #[inline] + pub fn filter bool>(self, predicate: P) -> Self { + if let COption::Some(x) = self { + if predicate(&x) { + return COption::Some(x); + } + } + COption::None + } + + /// Returns the option if it contains a value, otherwise returns `optb`. + /// + /// Arguments passed to `or` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`or_else`], which is + /// lazily evaluated. + /// + /// [`or_else`]: #method.or_else + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y = COption::None; + /// assert_eq!(x.or(y), COption::Some(2)); + /// + /// let x = COption::None; + /// let y = COption::Some(100); + /// assert_eq!(x.or(y), COption::Some(100)); + /// + /// let x = COption::Some(2); + /// let y = COption::Some(100); + /// assert_eq!(x.or(y), COption::Some(2)); + /// + /// let x: COption = COption::None; + /// let y = COption::None; + /// assert_eq!(x.or(y), COption::None); + /// ``` + #[inline] + pub fn or(self, optb: COption) -> COption { + match self { + COption::Some(_) => self, + COption::None => optb, + } + } + + /// Returns the option if it contains a value, otherwise calls `f` and + /// returns the result. + /// + /// # Examples + /// + /// ```ignore + /// fn nobody() -> COption<&'static str> { COption::None } + /// fn vikings() -> COption<&'static str> { COption::Some("vikings") } + /// + /// assert_eq!(COption::Some("barbarians").or_else(vikings), COption::Some("barbarians")); + /// assert_eq!(COption::None.or_else(vikings), COption::Some("vikings")); + /// assert_eq!(COption::None.or_else(nobody), COption::None); + /// ``` + #[inline] + pub fn or_else COption>(self, f: F) -> COption { + match self { + COption::Some(_) => self, + COption::None => f(), + } + } + + /// Returns [`COption::Some`] if exactly one of `self`, `optb` is [`COption::Some`], otherwise returns [`COption::None`]. + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y: COption = COption::None; + /// assert_eq!(x.xor(y), COption::Some(2)); + /// + /// let x: COption = COption::None; + /// let y = COption::Some(2); + /// assert_eq!(x.xor(y), COption::Some(2)); + /// + /// let x = COption::Some(2); + /// let y = COption::Some(2); + /// assert_eq!(x.xor(y), COption::None); + /// + /// let x: COption = COption::None; + /// let y: COption = COption::None; + /// assert_eq!(x.xor(y), COption::None); + /// ``` + #[inline] + pub fn xor(self, optb: COption) -> COption { + match (self, optb) { + (COption::Some(a), COption::None) => COption::Some(a), + (COption::None, COption::Some(b)) => COption::Some(b), + _ => COption::None, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Entry-like operations to insert if COption::None and return a reference + ///////////////////////////////////////////////////////////////////////// + + /// Inserts `v` into the option if it is [`COption::None`], then + /// returns a mutable reference to the contained value. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::None; + /// + /// { + /// let y: &mut u32 = x.get_or_insert(5); + /// assert_eq!(y, &5); + /// + /// *y = 7; + /// } + /// + /// assert_eq!(x, COption::Some(7)); + /// ``` + #[inline] + pub fn get_or_insert(&mut self, v: T) -> &mut T { + self.get_or_insert_with(|| v) + } + + /// Inserts a value computed from `f` into the option if it is [`COption::None`], then + /// returns a mutable reference to the contained value. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::None; + /// + /// { + /// let y: &mut u32 = x.get_or_insert_with(|| 5); + /// assert_eq!(y, &5); + /// + /// *y = 7; + /// } + /// + /// assert_eq!(x, COption::Some(7)); + /// ``` + #[inline] + pub fn get_or_insert_with T>(&mut self, f: F) -> &mut T { + if let COption::None = *self { + *self = COption::Some(f()) + } + + match *self { + COption::Some(ref mut v) => v, + COption::None => unsafe { hint::unreachable_unchecked() }, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Misc + ///////////////////////////////////////////////////////////////////////// + + /// Replaces the actual value in the option by the value given in parameter, + /// returning the old value if present, + /// leaving a [`COption::Some`] in its place without deinitializing either one. + /// + /// [`COption::Some`]: #variant.COption::Some + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::Some(2); + /// let old = x.replace(5); + /// assert_eq!(x, COption::Some(5)); + /// assert_eq!(old, COption::Some(2)); + /// + /// let mut x = COption::None; + /// let old = x.replace(3); + /// assert_eq!(x, COption::Some(3)); + /// assert_eq!(old, COption::None); + /// ``` + #[inline] + pub fn replace(&mut self, value: T) -> COption { + mem::replace(self, COption::Some(value)) + } +} + +impl COption<&T> { + /// Maps an `COption<&T>` to an `COption` by copying the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let x = 12; + /// let opt_x = COption::Some(&x); + /// assert_eq!(opt_x, COption::Some(&12)); + /// let copied = opt_x.copied(); + /// assert_eq!(copied, COption::Some(12)); + /// ``` + pub fn copied(self) -> COption { + self.map(|&t| t) + } +} + +impl COption<&mut T> { + /// Maps an `COption<&mut T>` to an `COption` by copying the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = 12; + /// let opt_x = COption::Some(&mut x); + /// assert_eq!(opt_x, COption::Some(&mut 12)); + /// let copied = opt_x.copied(); + /// assert_eq!(copied, COption::Some(12)); + /// ``` + pub fn copied(self) -> COption { + self.map(|&mut t| t) + } +} + +impl COption<&T> { + /// Maps an `COption<&T>` to an `COption` by cloning the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let x = 12; + /// let opt_x = COption::Some(&x); + /// assert_eq!(opt_x, COption::Some(&12)); + /// let cloned = opt_x.cloned(); + /// assert_eq!(cloned, COption::Some(12)); + /// ``` + pub fn cloned(self) -> COption { + self.map(|t| t.clone()) + } +} + +impl COption<&mut T> { + /// Maps an `COption<&mut T>` to an `COption` by cloning the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = 12; + /// let opt_x = COption::Some(&mut x); + /// assert_eq!(opt_x, COption::Some(&mut 12)); + /// let cloned = opt_x.cloned(); + /// assert_eq!(cloned, COption::Some(12)); + /// ``` + pub fn cloned(self) -> COption { + self.map(|t| t.clone()) + } +} + +impl COption { + /// Returns the contained value or a default + /// + /// Consumes the `self` argument then, if [`COption::Some`], returns the contained + /// value, otherwise if [`COption::None`], returns the [default value] for that + /// type. + /// + /// # Examples + /// + /// Converts a string to an integer, turning poorly-formed strings + /// into 0 (the default value for integers). [`parse`] converts + /// a string to any other type that implements [`FromStr`], returning + /// [`COption::None`] on error. + /// + /// ```ignore + /// let good_year_from_input = "1909"; + /// let bad_year_from_input = "190blarg"; + /// let good_year = good_year_from_input.parse().ok().unwrap_or_default(); + /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default(); + /// + /// assert_eq!(1909, good_year); + /// assert_eq!(0, bad_year); + /// ``` + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// [default value]: ../default/trait.Default.html#tymethod.default + /// [`parse`]: ../../std/primitive.str.html#method.parse + /// [`FromStr`]: ../../std/str/trait.FromStr.html + #[inline] + pub fn unwrap_or_default(self) -> T { + match self { + COption::Some(x) => x, + COption::None => Default::default(), + } + } +} + +impl COption { + /// Converts from `COption` (or `&COption`) to `COption<&T::Target>`. + /// + /// Leaves the original COption in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via [`Deref`]. + /// + /// [`Deref`]: ../../std/ops/trait.Deref.html + /// + /// # Examples + /// + /// ```ignore + /// #![feature(inner_deref)] + /// + /// let x: COption = COption::Some("hey".to_owned()); + /// assert_eq!(x.as_deref(), COption::Some("hey")); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.as_deref(), COption::None); + /// ``` + pub fn as_deref(&self) -> COption<&T::Target> { + self.as_ref().map(|t| t.deref()) + } +} + +impl COption { + /// Converts from `COption` (or `&mut COption`) to `COption<&mut T::Target>`. + /// + /// Leaves the original `COption` in-place, creating a new one containing a mutable reference to + /// the inner type's `Deref::Target` type. + /// + /// # Examples + /// + /// ```ignore + /// #![feature(inner_deref)] + /// + /// let mut x: COption = COption::Some("hey".to_owned()); + /// assert_eq!(x.as_deref_mut().map(|x| { + /// x.make_ascii_uppercase(); + /// x + /// }), COption::Some("HEY".to_owned().as_mut_str())); + /// ``` + pub fn as_deref_mut(&mut self) -> COption<&mut T::Target> { + self.as_mut().map(|t| t.deref_mut()) + } +} + +impl COption> { + /// Transposes an `COption` of a [`Result`] into a [`Result`] of an `COption`. + /// + /// [`COption::None`] will be mapped to [`Ok`]`(`[`COption::None`]`)`. + /// [`COption::Some`]`(`[`Ok`]`(_))` and [`COption::Some`]`(`[`Err`]`(_))` will be mapped to + /// [`Ok`]`(`[`COption::Some`]`(_))` and [`Err`]`(_)`. + /// + /// [`COption::None`]: #variant.COption::None + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`COption::Some`]: #variant.COption::Some + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ```ignore + /// #[derive(Debug, Eq, PartialEq)] + /// struct COption::SomeErr; + /// + /// let x: Result, COption::SomeErr> = Ok(COption::Some(5)); + /// let y: COption> = COption::Some(Ok(5)); + /// assert_eq!(x, y.transpose()); + /// ``` + #[inline] + pub fn transpose(self) -> Result, E> { + match self { + COption::Some(Ok(x)) => Ok(COption::Some(x)), + COption::Some(Err(e)) => Err(e), + COption::None => Ok(COption::None), + } + } +} + +// This is a separate function to reduce the code size of .expect() itself. +#[inline(never)] +#[cold] +fn expect_failed(msg: &str) -> ! { + panic!("{}", msg) +} + +// // This is a separate function to reduce the code size of .expect_none() itself. +// #[inline(never)] +// #[cold] +// fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! { +// panic!("{}: {:?}", msg, value) +// } + +///////////////////////////////////////////////////////////////////////////// +// Trait implementations +///////////////////////////////////////////////////////////////////////////// + +impl Clone for COption { + #[inline] + fn clone(&self) -> Self { + match self { + COption::Some(x) => COption::Some(x.clone()), + COption::None => COption::None, + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + match (self, source) { + (COption::Some(to), COption::Some(from)) => to.clone_from(from), + (to, from) => *to = from.clone(), + } + } +} + +impl Default for COption { + /// Returns [`COption::None`][COption::COption::None]. + /// + /// # Examples + /// + /// ```ignore + /// let opt: COption = COption::default(); + /// assert!(opt.is_none()); + /// ``` + #[inline] + fn default() -> COption { + COption::None + } +} + +impl From for COption { + fn from(val: T) -> COption { + COption::Some(val) + } +} + +impl<'a, T> From<&'a COption> for COption<&'a T> { + fn from(o: &'a COption) -> COption<&'a T> { + o.as_ref() + } +} + +impl<'a, T> From<&'a mut COption> for COption<&'a mut T> { + fn from(o: &'a mut COption) -> COption<&'a mut T> { + o.as_mut() + } +} + +impl COption> { + /// Converts from `COption>` to `COption` + /// + /// # Examples + /// Basic usage: + /// ```ignore + /// #![feature(option_flattening)] + /// let x: COption> = COption::Some(COption::Some(6)); + /// assert_eq!(COption::Some(6), x.flatten()); + /// + /// let x: COption> = COption::Some(COption::None); + /// assert_eq!(COption::None, x.flatten()); + /// + /// let x: COption> = COption::None; + /// assert_eq!(COption::None, x.flatten()); + /// ``` + /// Flattening once only removes one level of nesting: + /// ```ignore + /// #![feature(option_flattening)] + /// let x: COption>> = COption::Some(COption::Some(COption::Some(6))); + /// assert_eq!(COption::Some(COption::Some(6)), x.flatten()); + /// assert_eq!(COption::Some(6), x.flatten().flatten()); + /// ``` + #[inline] + pub fn flatten(self) -> COption { + self.and_then(convert::identity) + } +} diff --git a/program/src/processor.rs b/program/src/processor.rs new file mode 100644 index 0000000..c50d474 --- /dev/null +++ b/program/src/processor.rs @@ -0,0 +1,2232 @@ +//! Program state processor + +#![cfg(feature = "program")] + +use crate::{ + error::TokenError, + instruction::{is_valid_signer_index, TokenInstruction}, + option::COption, + state::{self, Account, Mint, Multisig}, +}; +use num_traits::FromPrimitive; +use solana_sdk::{ + account_info::{next_account_info, AccountInfo}, + decode_error::DecodeError, + entrypoint::ProgramResult, + info, + program_error::{PrintProgramError, ProgramError}, + pubkey::Pubkey, +}; +use std::mem::size_of; + +/// Program state handler. +pub struct Processor {} +impl Processor { + /// Processes an [InitializeMint](enum.TokenInstruction.html) instruction. + pub fn process_initialize_mint( + accounts: &[AccountInfo], + amount: u64, + decimals: u8, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let mint_info = next_account_info(account_info_iter)?; + + let mut mint_info_data = mint_info.data.borrow_mut(); + let mut mint: &mut Mint = state::unpack_unchecked(&mut mint_info_data)?; + if mint.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } + + let owner = if amount != 0 { + let dest_account_info = next_account_info(account_info_iter)?; + let mut dest_account_data = dest_account_info.data.borrow_mut(); + let mut dest_account: &mut Account = state::unpack(&mut dest_account_data)?; + + if mint_info.key != &dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + dest_account.amount = amount; + + if let Ok(owner_info) = next_account_info(account_info_iter) { + COption::Some(*owner_info.key) + } else { + COption::None + } + } else if let Ok(owner_info) = next_account_info(account_info_iter) { + COption::Some(*owner_info.key) + } else { + return Err(TokenError::OwnerRequiredIfNoInitialSupply.into()); + }; + + mint.owner = owner; + mint.decimals = decimals; + mint.is_initialized = true; + + Ok(()) + } + + /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. + pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let new_account_info = next_account_info(account_info_iter)?; + let mint_info = next_account_info(account_info_iter)?; + let owner_info = next_account_info(account_info_iter)?; + + let mut new_account_data = new_account_info.data.borrow_mut(); + let mut account: &mut Account = state::unpack_unchecked(&mut new_account_data)?; + if account.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } + + account.mint = *mint_info.key; + account.owner = *owner_info.key; + account.delegate = COption::None; + account.delegated_amount = 0; + account.is_initialized = true; + if *mint_info.key == crate::native_mint::id() { + account.is_native = true; + account.amount = new_account_info.lamports(); + } else { + account.is_native = false; + account.amount = 0; + }; + + Ok(()) + } + + /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. + pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let multisig_info = next_account_info(account_info_iter)?; + let mut multisig_account_data = multisig_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack_unchecked(&mut multisig_account_data)?; + if multisig.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } + + let signer_infos = account_info_iter.as_slice(); + multisig.m = m; + multisig.n = signer_infos.len() as u8; + if !is_valid_signer_index(multisig.n as usize) { + return Err(TokenError::InvalidNumberOfProvidedSigners.into()); + } + if !is_valid_signer_index(multisig.m as usize) { + return Err(TokenError::InvalidNumberOfRequiredSigners.into()); + } + for (i, signer_info) in signer_infos.iter().enumerate() { + multisig.signers[i] = *signer_info.key; + } + multisig.is_initialized = true; + + Ok(()) + } + + /// Processes a [Transfer](enum.TokenInstruction.html) instruction. + pub fn process_transfer( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + let dest_account_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + if source_account_info.key == dest_account_info.key { + return Ok(()); + } + + let mut source_data = source_account_info.data.borrow_mut(); + let mut source_account: &mut Account = state::unpack(&mut source_data)?; + let mut dest_data = dest_account_info.data.borrow_mut(); + let mut dest_account: &mut Account = state::unpack(&mut dest_data)?; + + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + if source_account.mint != dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + match source_account.delegate { + COption::Some(ref delegate) if authority_info.key == delegate => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount -= amount; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?, + }; + + source_account.amount -= amount; + dest_account.amount += amount; + + if source_account.is_native { + **source_account_info.lamports.borrow_mut() -= amount; + **dest_account_info.lamports.borrow_mut() += amount; + } + + Ok(()) + } + + /// Processes an [Approve](enum.TokenInstruction.html) instruction. + pub fn process_approve( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let mut source_account: &mut Account = state::unpack(&mut source_data)?; + let delegate_info = next_account_info(account_info_iter)?; + let owner_info = next_account_info(account_info_iter)?; + + Self::validate_owner( + program_id, + &source_account.owner, + owner_info, + account_info_iter.as_slice(), + )?; + + source_account.delegate = COption::Some(*delegate_info.key); + source_account.delegated_amount = amount; + + Ok(()) + } + + /// Processes an [Revoke](enum.TokenInstruction.html) instruction. + pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let mut source_account: &mut Account = state::unpack(&mut source_data)?; + let owner_info = next_account_info(account_info_iter)?; + + Self::validate_owner( + program_id, + &source_account.owner, + owner_info, + account_info_iter.as_slice(), + )?; + + source_account.delegate = COption::None; + source_account.delegated_amount = 0; + + Ok(()) + } + + /// Processes a [SetOwner](enum.TokenInstruction.html) instruction. + pub fn process_set_owner(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let account_info = next_account_info(account_info_iter)?; + let new_owner_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + if account_info.data_len() == size_of::() { + let mut account_data = account_info.data.borrow_mut(); + let mut account: &mut Account = state::unpack(&mut account_data)?; + + Self::validate_owner( + program_id, + &account.owner, + authority_info, + account_info_iter.as_slice(), + )?; + + account.owner = *new_owner_info.key; + } else if account_info.data_len() == size_of::() { + let mut account_data = account_info.data.borrow_mut(); + let mut mint: &mut Mint = state::unpack(&mut account_data)?; + + match mint.owner { + COption::Some(ref owner) => { + Self::validate_owner( + program_id, + owner, + authority_info, + account_info_iter.as_slice(), + )?; + } + COption::None => return Err(TokenError::FixedSupply.into()), + } + mint.owner = COption::Some(*new_owner_info.key); + } else { + return Err(ProgramError::InvalidArgument); + } + + Ok(()) + } + + /// Processes a [MintTo](enum.TokenInstruction.html) instruction. + pub fn process_mint_to( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let mint_info = next_account_info(account_info_iter)?; + let dest_account_info = next_account_info(account_info_iter)?; + let owner_info = next_account_info(account_info_iter)?; + + let mut dest_account_data = dest_account_info.data.borrow_mut(); + let mut dest_account: &mut Account = state::unpack(&mut dest_account_data)?; + + if dest_account.is_native { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key != &dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mut mint_info_data = mint_info.data.borrow_mut(); + let mint: &mut Mint = state::unpack(&mut mint_info_data)?; + + match mint.owner { + COption::Some(owner) => { + Self::validate_owner(program_id, &owner, owner_info, account_info_iter.as_slice())?; + } + COption::None => { + return Err(TokenError::FixedSupply.into()); + } + } + + dest_account.amount += amount; + + Ok(()) + } + + /// Processes a [Burn](enum.TokenInstruction.html) instruction. + pub fn process_burn( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let source_account: &mut Account = state::unpack(&mut source_data)?; + + if source_account.is_native { + return Err(TokenError::NativeNotSupported.into()); + } + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + + match source_account.delegate { + COption::Some(ref delegate) if authority_info.key == delegate => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; + + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount -= amount; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?, + } + + source_account.amount -= amount; + + Ok(()) + } + + /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. + pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + let dest_account_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let source_account: &mut Account = state::unpack(&mut source_data)?; + + if !source_account.is_native { + return Err(TokenError::NonNativeNotSupported.into()); + } + + Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?; + + **dest_account_info.lamports.borrow_mut() += source_account_info.lamports(); + **source_account_info.lamports.borrow_mut() = 0; + source_account.amount = 0; + + Ok(()) + } + + /// Processes an [Instruction](enum.Instruction.html). + pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { + let instruction = TokenInstruction::unpack(input)?; + + match instruction { + TokenInstruction::InitializeMint { amount, decimals } => { + info!("Instruction: InitializeMint"); + Self::process_initialize_mint(accounts, amount, decimals) + } + TokenInstruction::InitializeAccount => { + info!("Instruction: InitializeAccount"); + Self::process_initialize_account(accounts) + } + TokenInstruction::InitializeMultisig { m } => { + info!("Instruction: InitializeMultisig"); + Self::process_initialize_multisig(accounts, m) + } + TokenInstruction::Transfer { amount } => { + info!("Instruction: Transfer"); + Self::process_transfer(program_id, accounts, amount) + } + TokenInstruction::Approve { amount } => { + info!("Instruction: Approve"); + Self::process_approve(program_id, accounts, amount) + } + TokenInstruction::Revoke => { + info!("Instruction: Revoke"); + Self::process_revoke(program_id, accounts) + } + TokenInstruction::SetOwner => { + info!("Instruction: SetOwner"); + Self::process_set_owner(program_id, accounts) + } + TokenInstruction::MintTo { amount } => { + info!("Instruction: MintTo"); + Self::process_mint_to(program_id, accounts, amount) + } + TokenInstruction::Burn { amount } => { + info!("Instruction: Burn"); + Self::process_burn(program_id, accounts, amount) + } + TokenInstruction::CloseAccount => { + info!("Instruction: CloseAccount"); + Self::process_close_account(program_id, accounts) + } + } + } + + /// Validates owner(s) are present + pub fn validate_owner( + program_id: &Pubkey, + expected_owner: &Pubkey, + owner_account_info: &AccountInfo, + signers: &[AccountInfo], + ) -> ProgramResult { + if expected_owner != owner_account_info.key { + return Err(TokenError::OwnerMismatch.into()); + } + if program_id == owner_account_info.owner + && owner_account_info.data_len() == std::mem::size_of::() + { + let mut owner_data = owner_account_info.data.borrow_mut(); + let multisig: &mut Multisig = state::unpack(&mut owner_data)?; + let mut num_signers = 0; + for signer in signers.iter() { + if multisig.signers[0..multisig.n as usize].contains(signer.key) { + if !signer.is_signer { + return Err(ProgramError::MissingRequiredSignature); + } + num_signers += 1; + } + } + if num_signers < multisig.m { + return Err(ProgramError::MissingRequiredSignature); + } + } else if !owner_account_info.is_signer { + return Err(ProgramError::MissingRequiredSignature); + } + Ok(()) + } +} + +impl PrintProgramError for TokenError { + fn print(&self) + where + E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, + { + match self { + TokenError::InsufficientFunds => info!("Error: insufficient funds"), + TokenError::MintMismatch => info!("Error: Account not associated with this Mint"), + TokenError::OwnerMismatch => info!("Error: owner does not match"), + TokenError::FixedSupply => info!("Error: the total supply of this token is fixed"), + TokenError::AlreadyInUse => info!("Error: account or token already in use"), + TokenError::OwnerRequiredIfNoInitialSupply => { + info!("Error: An owner is required if supply is zero") + } + TokenError::InvalidNumberOfProvidedSigners => { + info!("Error: Invalid number of provided signers") + } + TokenError::InvalidNumberOfRequiredSigners => { + info!("Error: Invalid number of required signers") + } + TokenError::UninitializedState => info!("Error: State is uninitialized"), + TokenError::NativeNotSupported => { + info!("Error: Instruction does not support native tokens") + } + TokenError::NonNativeNotSupported => { + info!("Error: Instruction does not support non-native tokens") + } + TokenError::InvalidInstruction => info!("Error: Invalid instruction"), + } + } +} + +// Pull in syscall stubs when building for non-BPF targets +#[cfg(not(target_arch = "bpf"))] +solana_sdk::program_stubs!(); + +#[cfg(test)] +mod tests { + use super::*; + use crate::instruction::{ + approve, burn, close_account, initialize_account, initialize_mint, initialize_multisig, + mint_to, revoke, set_owner, transfer, MAX_SIGNERS, + }; + use solana_sdk::{ + account::Account as SolanaAccount, account_info::create_is_signer_account_infos, + clock::Epoch, instruction::Instruction, + }; + + fn pubkey_rand() -> Pubkey { + Pubkey::new(&rand::random::<[u8; 32]>()) + } + + fn do_process_instruction( + instruction: Instruction, + accounts: Vec<&mut SolanaAccount>, + ) -> ProgramResult { + let mut meta = instruction + .accounts + .iter() + .zip(accounts) + .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) + .collect::>(); + + let account_infos = create_is_signer_account_infos(&mut meta); + Processor::process(&instruction.program_id, &account_infos, &instruction.data) + } + + fn return_token_error_as_program_error() -> ProgramError { + TokenError::MintMismatch.into() + } + + #[test] + fn test_print_error() { + let error = return_token_error_as_program_error(); + error.print::(); + } + + #[test] + #[should_panic(expected = "Custom(1)")] + fn test_error_unwrap() { + Err::<(), ProgramError>(return_token_error_as_program_error()).unwrap(); + } + + #[test] + fn test_unique_account_sizes() { + assert_ne!(size_of::(), 0); + assert_ne!(size_of::(), size_of::()); + assert_ne!(size_of::(), size_of::()); + assert_ne!(size_of::(), 0); + assert_ne!(size_of::(), size_of::()); + assert_ne!(size_of::(), 0); + } + + #[test] + fn test_initialize_mint() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + + // account not created + assert_eq!( + Err(TokenError::UninitializedState.into()), + do_process_instruction( + initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), + vec![&mut mint_account, &mut account_account] + ) + ); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut owner_account, &mut mint_account], + ) + .unwrap(); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), + vec![&mut mint_account, &mut account_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut owner_account, &mut mint_account], + ) + .unwrap(); + + // mismatch account + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + initialize_mint(&program_id, &mint2_key, Some(&account2_key), None, 1000, 2) + .unwrap(), + vec![&mut mint2_account, &mut account2_account] + ) + ); + + // create twice + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), + vec![&mut mint_account, &mut account_account] + ) + ); + } + + #[test] + fn test_initialize_mint_account() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create twice + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + } + + #[test] + fn test_transfer() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let delegate_key = pubkey_rand(); + let mut delegate_account = SolanaAccount::default(); + let mismatch_key = pubkey_rand(); + let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), + vec![&mut mint_account, &mut account_account], + ) + .unwrap(); + + // missing signer + let mut instruction = transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // mismatch mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &mismatch_key, + &owner_key, + &[], + 1000 + ) + .unwrap(), + vec![ + &mut account_account, + &mut mismatch_account, + &mut owner_account, + ], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner2_key, + &[], + 1000 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // transfer + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // transfer half back + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // transfer rest + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // transfer to self + { + let instruction = transfer( + &program_id, + &account_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(); + let account_account_info = AccountInfo::from(( + &instruction.accounts[0].pubkey, + instruction.accounts[0].is_signer, + &mut account_account, + )); + let owner_account_info = AccountInfo::from(( + &instruction.accounts[2].pubkey, + instruction.accounts[2].is_signer, + &mut owner_account, + )); + Processor::process( + &instruction.program_id, + &[ + account_account_info.clone(), + account_account_info, + owner_account_info, + ], + &instruction.data, + ) + .unwrap() + } + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, 1000); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // transfer via delegate + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + .unwrap(); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + + // transfer rest + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 900, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds in source account via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + } + + #[test] + fn test_mintable_token_with_zero_supply() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut owner_account, &mut mint_account], + ) + .unwrap(); + + // create mint-able token without owner + let mut instruction = + initialize_mint(&program_id, &mint_key, None, Some(&owner_key), 0, 2).unwrap(); + instruction.accounts.pop(); + assert_eq!( + Err(TokenError::OwnerRequiredIfNoInitialSupply.into()), + do_process_instruction(instruction, vec![&mut mint_account]) + ); + + // create mint-able token with zero supply + let amount = 0; + let decimals = 2; + do_process_instruction( + initialize_mint( + &program_id, + &mint_key, + None, + Some(&owner_key), + amount, + decimals, + ) + .unwrap(), + vec![&mut mint_account, &mut account_account], + ) + .unwrap(); + let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + assert_eq!( + *mint, + Mint { + owner: COption::Some(owner_key), + decimals, + is_initialized: true, + } + ); + + // mint to + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(dest_account.amount, 42); + } + + #[test] + fn test_approve() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let delegate_key = pubkey_rand(); + let mut delegate_account = SolanaAccount::default(); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut owner_account, &mut mint_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut owner_account, &mut mint_account], + ) + .unwrap(); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), + vec![&mut mint_account, &mut account_account], + ) + .unwrap(); + + // missing signer + let mut instruction = approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // no owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner2_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner2_account, + ], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // revoke delegate + do_process_instruction( + revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + } + + #[test] + fn test_set_owner() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let owner3_key = pubkey_rand(); + let mut owner3_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + + // invalid account + assert_eq!( + Err(TokenError::UninitializedState.into()), + do_process_instruction( + set_owner(&program_id, &account_key, &owner2_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut owner2_account, + &mut owner_account, + ], + ) + ); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_owner(&program_id, &account_key, &owner_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut owner_account, + &mut owner2_account, + ], + ) + ); + + // owner did not sign + let mut instruction = + set_owner(&program_id, &account_key, &owner2_key, &owner_key, &[]).unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut owner2_account, + &mut owner_account, + ], + ) + ); + + // set owner + do_process_instruction( + set_owner(&program_id, &account_key, &owner2_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut owner2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // create new mint with owner + do_process_instruction( + initialize_mint( + &program_id, + &mint_key, + Some(&account_key), + Some(&owner_key), + 1000, + 2, + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // wrong account + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_owner(&program_id, &mint_key, &owner3_key, &owner2_key, &[]).unwrap(), + vec![&mut mint_account, &mut owner3_account, &mut owner2_account], + ) + ); + + // owner did not sign + let mut instruction = + set_owner(&program_id, &mint_key, &owner2_key, &owner_key, &[]).unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![&mut mint_account, &mut owner2_account, &mut owner_account], + ) + ); + + // set owner + do_process_instruction( + set_owner(&program_id, &mint_key, &owner2_key, &owner_key, &[]).unwrap(), + vec![&mut mint_account, &mut owner2_account, &mut owner_account], + ) + .unwrap(); + + // create new mint without owner + do_process_instruction( + initialize_mint(&program_id, &mint2_key, Some(&account2_key), None, 1000, 2).unwrap(), + vec![&mut mint2_account, &mut account2_account], + ) + .unwrap(); + + // set owner for non-mint-able token + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_owner(&program_id, &mint2_key, &owner2_key, &owner_key, &[]).unwrap(), + vec![&mut mint_account, &mut owner2_account, &mut owner_account], + ) + ); + } + + #[test] + fn test_mint_to() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let mismatch_key = pubkey_rand(); + let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + let uninitialized_key = pubkey_rand(); + let mut uninitialized_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // create new mint with owner + do_process_instruction( + initialize_mint( + &program_id, + &mint_key, + Some(&account_key), + Some(&owner_key), + 1000, + 2, + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // mint to + do_process_instruction( + mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + .unwrap(); + + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let dest_account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert_eq!(dest_account.amount, 42); + + // missing signer + let mut instruction = + mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + ); + + // mismatch account + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // uninitialized destination account + assert_eq!( + Err(TokenError::UninitializedState.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &uninitialized_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![ + &mut mint_account, + &mut uninitialized_account, + &mut owner_account, + ], + ) + ); + } + + #[test] + fn test_burn() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let delegate_key = pubkey_rand(); + let mut delegate_account = SolanaAccount::default(); + let mismatch_key = pubkey_rand(); + let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), + vec![&mut mint_account, &mut account_account], + ) + .unwrap(); + + // missing signer + let mut instruction = burn(&program_id, &account_key, &delegate_key, &[], 42).unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + instruction, + vec![&mut account_account, &mut delegate_account], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner2_key, &[], 42).unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + ); + + // burn + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, 1000 - 42); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 84, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // not a delegate of source account + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // burn via delegate + do_process_instruction( + burn(&program_id, &account_key, &delegate_key, &[], 84).unwrap(), + vec![&mut account_account, &mut delegate_account], + ) + .unwrap(); + + // match + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, 1000 - 42 - 84); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn(&program_id, &account_key, &delegate_key, &[], 100).unwrap(), + vec![&mut account_account, &mut delegate_account], + ) + ); + } + + #[test] + fn test_multisig() { + let program_id = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let account_key = pubkey_rand(); + let mut account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let multisig_key = pubkey_rand(); + let mut multisig_account = SolanaAccount::new(0, size_of::(), &program_id); + let multisig_delegate_key = pubkey_rand(); + let mut multisig_delegate_account = + SolanaAccount::new(0, size_of::(), &program_id); + let signer_keys = vec![pubkey_rand(); MAX_SIGNERS]; + let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().map(|key| key).collect(); + let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; + + // single signer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // multiple signer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig( + &program_id, + &multisig_delegate_key, + &signer_key_refs, + MAX_SIGNERS as u8, + ) + .unwrap(), + vec![ + &mut multisig_delegate_account, + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // create account with multisig owner + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), + vec![&mut account, &mut mint_account, &mut multisig_account], + ) + .unwrap(); + + // create another account with multisig owner + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &mint_key, + &multisig_delegate_key, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut multisig_account, + ], + ) + .unwrap(); + + // create new m int with multisig owner + do_process_instruction( + initialize_mint( + &program_id, + &mint_key, + Some(&account_key), + Some(&multisig_key), + 1000, + 2, + ) + .unwrap(), + vec![&mut mint_account, &mut account, &mut multisig_account], + ) + .unwrap(); + + // approve + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + approve( + &program_id, + &account_key, + &multisig_delegate_key, + &multisig_key, + &[&signer_keys[0]], + 100, + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_delegate_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // transfer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut account2_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // transfer via delegate + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &multisig_delegate_key, + &signer_key_refs, + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut account2_account, + &mut multisig_delegate_account, + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // mint to + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // burn + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + burn( + &program_id, + &account_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // burn via delegate + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + burn( + &program_id, + &account_key, + &multisig_delegate_key, + &signer_key_refs, + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_delegate_account, + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // do SetOwner on mint + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + set_owner( + &program_id, + &mint_key, + &owner_key, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut mint_account, + &mut owner_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // do SetOwner on account + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + set_owner( + &program_id, + &account_key, + &owner_key, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut account, + &mut owner_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + } + + #[test] + fn test_validate_owner() { + let program_id = pubkey_rand(); + let owner_key = pubkey_rand(); + let mut signer_keys = [Pubkey::default(); MAX_SIGNERS]; + for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) { + *signer_key = pubkey_rand(); + } + let mut signer_lamports = 0; + let mut signer_data = vec![]; + let mut signers = vec![ + AccountInfo::new( + &owner_key, + true, + false, + &mut signer_lamports, + &mut signer_data, + &program_id, + false, + Epoch::default(), + ); + MAX_SIGNERS + 1 + ]; + for (signer, key) in signers.iter_mut().zip(&signer_keys) { + signer.key = key; + } + let mut lamports = 0; + let mut data = vec![0; size_of::()]; + let mut multisig: &mut Multisig = state::unpack_unchecked(&mut data).unwrap(); + multisig.m = MAX_SIGNERS as u8; + multisig.n = MAX_SIGNERS as u8; + multisig.signers = signer_keys; + multisig.is_initialized = true; + let owner_account_info = AccountInfo::new( + &owner_key, + false, + false, + &mut lamports, + &mut data, + &program_id, + false, + Epoch::default(), + ); + + // full 11 of 11 + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); + + // 1 of 11 + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 1; + } + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); + + // 2:1 + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 1; + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) + ); + + // 0:11 + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 0; + multisig.n = 11; + } + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); + + // 2:11 but 0 provided + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 11; + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &[]) + ); + // 2:11 but 1 provided + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 11; + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[0..1]) + ); + + // 2:11, 2 from middle provided + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 11; + } + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[5..7]) + .unwrap(); + + // 11:11, one is not a signer + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 11; + } + signers[5].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) + ); + signers[5].is_signer = true; + } + + #[test] + fn test_close_account() { + let program_id = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(2, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(2, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + + // uninitialized + assert_eq!( + Err(TokenError::UninitializedState.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + ); + + // initialize non-native account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account.amount, 2); + + // close non-native account + assert_eq!( + Err(TokenError::NonNativeNotSupported.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + ); + assert_eq!(account_account.lamports, 42); + + // close native account + do_process_instruction( + close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account2_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack_unchecked(&mut account2_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account.amount, 0); + assert_eq!(account3_account.lamports, 4); + } + + #[test] + fn test_native_token() { + let program_id = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(2, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(2, 0, &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account.amount, 42); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account.amount, 2); + + // mint_to unsupported + assert_eq!( + Err(TokenError::NativeNotSupported.into()), + do_process_instruction( + mint_to( + &program_id, + &crate::native_mint::id(), + &account_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + + // burn unsupported + assert_eq!( + Err(TokenError::NativeNotSupported.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // initialize native account + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 40, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account_account.lamports, 2); + assert_eq!(account.amount, 2); + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account2_account.lamports, 42); + assert_eq!(account.amount, 42); + + // close native account + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account_account.lamports, 0); + assert_eq!(account.amount, 0); + assert_eq!(account3_account.lamports, 4); + } +} diff --git a/program/src/state.rs b/program/src/state.rs new file mode 100644 index 0000000..3b63f4f --- /dev/null +++ b/program/src/state.rs @@ -0,0 +1,92 @@ +//! State transition types + +use crate::{error::TokenError, instruction::MAX_SIGNERS, option::COption}; +use solana_sdk::{program_error::ProgramError, pubkey::Pubkey}; +use std::mem::size_of; + +/// Mint data. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Mint { + /// Optional owner, used to mint new tokens. The owner may only + /// be provided during mint creation. If no owner is present then the mint + /// has a fixed supply and no further tokens may be minted. + pub owner: COption, + /// Number of base 10 digits to the right of the decimal place. + pub decimals: u8, + /// Is `true` if this structure has been initialized + pub is_initialized: bool, +} +impl IsInitialized for Mint { + fn is_initialized(&self) -> bool { + self.is_initialized + } +} + +/// Account data. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Account { + /// The mint associated with this account + pub mint: Pubkey, + /// The owner of this account. + pub owner: Pubkey, + /// The amount of tokens this account holds. + pub amount: u64, + /// If `delegate` is `Some` then `delegated_amount` represents + /// the amount authorized by the delegate + pub delegate: COption, + /// Is `true` if this structure has been initialized + pub is_initialized: bool, + /// Is this a native token + pub is_native: bool, + /// The amount delegated + pub delegated_amount: u64, +} +impl IsInitialized for Account { + fn is_initialized(&self) -> bool { + self.is_initialized + } +} + +/// Multisignature data. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Multisig { + /// Number of signers required + pub m: u8, + /// Number of valid signers + pub n: u8, + /// Is `true` if this structure has been initialized + pub is_initialized: bool, + /// Signer public keys + pub signers: [Pubkey; MAX_SIGNERS], +} +impl IsInitialized for Multisig { + fn is_initialized(&self) -> bool { + self.is_initialized + } +} + +/// Check is a token state is initialized +pub trait IsInitialized { + /// Is initialized + fn is_initialized(&self) -> bool; +} + +/// Unpacks a token state from a bytes buffer while assuring that the state is initialized. +pub fn unpack(input: &mut [u8]) -> Result<&mut T, ProgramError> { + let mut_ref: &mut T = unpack_unchecked(input)?; + if !mut_ref.is_initialized() { + return Err(TokenError::UninitializedState.into()); + } + Ok(mut_ref) +} +/// Unpacks a token state from a bytes buffer without checking that the state is initialized. +pub fn unpack_unchecked(input: &mut [u8]) -> Result<&mut T, ProgramError> { + if input.len() != size_of::() { + return Err(ProgramError::InvalidAccountData); + } + #[allow(clippy::cast_ptr_alignment)] + Ok(unsafe { &mut *(&mut input[0] as *mut u8 as *mut T) }) +} From 65859f5291f3b03c43af9ae5bfde1a4121f8b3f4 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Sat, 8 Aug 2020 11:24:21 -0700 Subject: [PATCH 010/335] Relocate js --- program/js/.eslintignore | 1 - program/js/.eslintrc.js | 56 - program/js/.flowconfig | 20 - program/js/.gitignore | 1 - program/js/.prettierrc.yaml | 7 - program/js/README.md | 69 - program/js/babel.config.json | 17 - program/js/babel.rollup.config.json | 18 - program/js/cli/main.js | 58 - program/js/cli/token-test.js | 500 - program/js/client/layout.js | 47 - program/js/client/token.js | 1242 --- .../client/util/new-account-with-lamports.js | 25 - .../util/new-system-account-with-airdrop.js | 17 - .../util/send-and-confirm-transaction.js | 21 - program/js/client/util/sleep.js | 6 - program/js/client/util/store.js | 26 - program/js/cluster-devnet.env | 2 - program/js/cluster-mainnet-beta.env | 2 - program/js/cluster-testnet.env | 2 - program/js/flow-typed/bn.js.js | 4 - program/js/flow-typed/bs58.js | 6 - program/js/flow-typed/buffer-layout.js | 4 - .../js/flow-typed/mkdirp-promise_vx.x.x.js | 32 - program/js/flow-typed/npm/mz_vx.x.x.js | 73 - program/js/flow-typed/semver.js | 3 - program/js/module.d.ts | 160 - program/js/module.flow.js | 163 - program/js/package-lock.json | 8383 ----------------- program/js/package.json | 78 - program/js/rollup.config.js | 74 - program/js/url.js | 31 - 32 files changed, 11148 deletions(-) delete mode 100644 program/js/.eslintignore delete mode 100644 program/js/.eslintrc.js delete mode 100644 program/js/.flowconfig delete mode 100644 program/js/.gitignore delete mode 100644 program/js/.prettierrc.yaml delete mode 100644 program/js/README.md delete mode 100644 program/js/babel.config.json delete mode 100644 program/js/babel.rollup.config.json delete mode 100644 program/js/cli/main.js delete mode 100644 program/js/cli/token-test.js delete mode 100644 program/js/client/layout.js delete mode 100644 program/js/client/token.js delete mode 100644 program/js/client/util/new-account-with-lamports.js delete mode 100644 program/js/client/util/new-system-account-with-airdrop.js delete mode 100644 program/js/client/util/send-and-confirm-transaction.js delete mode 100644 program/js/client/util/sleep.js delete mode 100644 program/js/client/util/store.js delete mode 100644 program/js/cluster-devnet.env delete mode 100644 program/js/cluster-mainnet-beta.env delete mode 100644 program/js/cluster-testnet.env delete mode 100644 program/js/flow-typed/bn.js.js delete mode 100644 program/js/flow-typed/bs58.js delete mode 100644 program/js/flow-typed/buffer-layout.js delete mode 100644 program/js/flow-typed/mkdirp-promise_vx.x.x.js delete mode 100644 program/js/flow-typed/npm/mz_vx.x.x.js delete mode 100644 program/js/flow-typed/semver.js delete mode 100644 program/js/module.d.ts delete mode 100644 program/js/module.flow.js delete mode 100644 program/js/package-lock.json delete mode 100644 program/js/package.json delete mode 100644 program/js/rollup.config.js delete mode 100644 program/js/url.js diff --git a/program/js/.eslintignore b/program/js/.eslintignore deleted file mode 100644 index 502167f..0000000 --- a/program/js/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -/lib diff --git a/program/js/.eslintrc.js b/program/js/.eslintrc.js deleted file mode 100644 index 96d3aae..0000000 --- a/program/js/.eslintrc.js +++ /dev/null @@ -1,56 +0,0 @@ -// eslint-disable-next-line -module.exports = { - // eslint-disable-line import/no-commonjs - env: { - browser: true, - es6: true, - node: true, - }, - extends: [ - 'eslint:recommended', - 'plugin:import/errors', - 'plugin:import/warnings', - ], - parser: 'babel-eslint', - parserOptions: { - sourceType: 'module', - ecmaVersion: 8, - }, - rules: { - 'no-trailing-spaces': ['error'], - 'import/first': ['error'], - 'import/no-commonjs': ['error'], - 'import/order': [ - 'error', - { - groups: [ - ['internal', 'external', 'builtin'], - ['index', 'sibling', 'parent'], - ], - 'newlines-between': 'always', - }, - ], - indent: [ - 'error', - 2, - { - MemberExpression: 1, - SwitchCase: 1, - }, - ], - 'linebreak-style': ['error', 'unix'], - 'no-console': [0], - quotes: [ - 'error', - 'single', - {avoidEscape: true, allowTemplateLiterals: true}, - ], - 'require-await': ['error'], - semi: ['error', 'always'], - }, - settings: { - react: { - version: 'detect', - }, - }, -}; diff --git a/program/js/.flowconfig b/program/js/.flowconfig deleted file mode 100644 index 486f7e7..0000000 --- a/program/js/.flowconfig +++ /dev/null @@ -1,20 +0,0 @@ -[ignore] -/node_modules/* - -[include] - -[libs] -node_modules/@solana/web3.js/module.flow.js -flow-typed/ - -[options] - -emoji=true -esproposal.class_instance_fields=enable -esproposal.class_static_fields=enable -esproposal.decorators=ignore -esproposal.export_star_as=enable -module.system.node.resolve_dirname=./src -module.use_strict=true -experimental.const_params=true -include_warnings=true diff --git a/program/js/.gitignore b/program/js/.gitignore deleted file mode 100644 index a65b417..0000000 --- a/program/js/.gitignore +++ /dev/null @@ -1 +0,0 @@ -lib diff --git a/program/js/.prettierrc.yaml b/program/js/.prettierrc.yaml deleted file mode 100644 index 8deef5d..0000000 --- a/program/js/.prettierrc.yaml +++ /dev/null @@ -1,7 +0,0 @@ -arrowParens: "avoid" -bracketSpacing: false -jsxBracketSameLine: false -semi: true -singleQuote: true -tabWidth: 2 -trailingComma: "all" diff --git a/program/js/README.md b/program/js/README.md deleted file mode 100644 index 5deb943..0000000 --- a/program/js/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# Token Javascript API - -The Token JavaScript library comprises: - -* A library to interact with the on-chain program -* A test client that exercises the program -* Scripts to facilitate building the program - -## Getting Started - -First fetch the npm dependencies, including `@solana/web3.js`, by running: -```bash -$ npm install -``` - -### Select a Network - -The client connects to a local Solana cluster by default. - -To enable on-chain program logs, set the `RUST_LOG` environment variable: - -```bash -$ export RUST_LOG=solana_runtime::native_loader=trace,solana_runtime::system_instruction_processor=trace,solana_runtime::bank=debug,solana_bpf_loader=debug,solana_rbpf=debug -``` - -To start a local Solana cluster run: -```bash -$ npm run localnet:update -$ npm run localnet:up -``` - -Solana cluster logs are available with: -```bash -$ npm run localnet:logs -``` - -For more details on working with a local cluster, see the [full -instructions](https://github.com/solana-labs/solana-web3.js#local-network). - -### Build the on-chain program - -```bash -$ npm run build:program -``` - -### Run the test client - -```bash -$ npm run start -``` - -## Pointing to a public Solana cluster - -Solana maintains three public clusters: -- `devnet` - Development cluster with airdrops enabled -- `testnet` - Tour De Sol test cluster without airdrops enabled -- `mainnet-beta` - Main cluster - -Use npm scripts to configure which cluster. - -To point to `devnet`: -```bash -$ npm run cluster:devnet -``` - -To point back to the local cluster: -```bash -$ npm run cluster:localnet -``` diff --git a/program/js/babel.config.json b/program/js/babel.config.json deleted file mode 100644 index 9c47e88..0000000 --- a/program/js/babel.config.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "node": "10" - } - } - ], - "@babel/preset-flow" - ], - "plugins": [ - "@babel/plugin-transform-runtime", - "@babel/plugin-proposal-class-properties" - ] -} diff --git a/program/js/babel.rollup.config.json b/program/js/babel.rollup.config.json deleted file mode 100644 index ee7e695..0000000 --- a/program/js/babel.rollup.config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "modules": false, - "targets": { - "node": "10" - } - } - ], - "@babel/preset-flow" - ], - "plugins": [ - "@babel/plugin-transform-runtime", - "@babel/plugin-proposal-class-properties" - ] -} diff --git a/program/js/cli/main.js b/program/js/cli/main.js deleted file mode 100644 index ee36e4f..0000000 --- a/program/js/cli/main.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Exercises the token program - * - * @flow - */ - -import { - loadTokenProgram, - createMint, - createAccount, - transfer, - approveRevoke, - invalidApprove, - failOnApproveOverspend, - setOwner, - mintTo, - multisig, - burn, - failOnCloseAccount, - nativeToken, -} from './token-test'; - -async function main() { - console.log('Run test: loadTokenProgram'); - await loadTokenProgram(); - console.log('Run test: createMint'); - await createMint(); - console.log('Run test: createAccount'); - await createAccount(); - console.log('Run test: transfer'); - await transfer(); - console.log('Run test: approveRevoke'); - await approveRevoke(); - console.log('Run test: invalidApprove'); - await invalidApprove(); - console.log('Run test: failOnApproveOverspend'); - await failOnApproveOverspend(); - console.log('Run test: setOwner'); - await setOwner(); - console.log('Run test: mintTo'); - await mintTo(); - console.log('Run test: multisig'); - await multisig(); - console.log('Run test: burn'); - await burn(); - console.log('Run test: failOnCloseAccount'); - await failOnCloseAccount(); - console.log('Run test: nativeToken'); - await nativeToken(); - console.log('Success\n'); -} - -main() - .catch(err => { - console.error(err); - process.exit(-1); - }) - .then(() => process.exit()); diff --git a/program/js/cli/token-test.js b/program/js/cli/token-test.js deleted file mode 100644 index c0523d9..0000000 --- a/program/js/cli/token-test.js +++ /dev/null @@ -1,500 +0,0 @@ -// @flow - -import fs from 'mz/fs'; -import {Account, Connection, BpfLoader, PublicKey} from '@solana/web3.js'; -import semver from 'semver'; - -import {Token, u64} from '../client/token'; -import {url} from '../url'; -import {newAccountWithLamports} from '../client/util/new-account-with-lamports'; -import {sleep} from '../client/util/sleep'; -import {Store} from '../client/util/store'; - -// Loaded token program's program id -let programId: PublicKey; - -// A token created by the next test and used by all subsequent tests -let mintOwner: Account; -let testToken: Token; -// Initial token account -let testAccountOwner: Account; -let testAccount: PublicKey; - -// A mintable token used by multiple tests -let mintableOwner: Account; -let testMintableToken: Token; -// Initial token account -let testMintableAccountOwner: Account; -let testMintableAccount: PublicKey; - -function assert(condition, message) { - if (!condition) { - console.log(Error().stack + ':token-test.js'); - throw message || 'Assertion failed'; - } -} - -async function didThrow(func, args): Promise { - try { - await func.apply(args); - } catch (e) { - return true; - } - return false; -} - -let connection; -async function getConnection(): Promise { - if (connection) return connection; - - let newConnection = new Connection(url, 'recent'); - const version = await newConnection.getVersion(); - - // commitment params are only supported >= 0.21.0 - const solanaCoreVersion = version['solana-core'].split(' ')[0]; - if (semver.gte(solanaCoreVersion, '0.21.0')) { - newConnection = new Connection(url, 'recent'); - } - - // eslint-disable-next-line require-atomic-updates - connection = newConnection; - console.log('Connection to cluster established:', url, version); - return connection; -} - -async function loadProgram( - connection: Connection, - path: string, -): Promise { - const NUM_RETRIES = 500; /* allow some number of retries */ - const data = await fs.readFile(path); - const {feeCalculator} = await connection.getRecentBlockhash(); - const balanceNeeded = - feeCalculator.lamportsPerSignature * - (BpfLoader.getMinNumSignatures(data.length) + NUM_RETRIES) + - (await connection.getMinimumBalanceForRentExemption(data.length)); - - const from = await newAccountWithLamports(connection, balanceNeeded); - const program_account = new Account(); - console.log('Loading program:', path); - await BpfLoader.load(connection, from, program_account, data); - return program_account.publicKey; -} - -async function GetPrograms(connection: Connection): Promise { - const store = new Store(); - let tokenProgramId = null; - try { - const config = await store.load('config.json'); - console.log('Using pre-loaded Token program'); - console.log( - ' Note: To reload program remove client/util/store/config.json', - ); - tokenProgramId = new PublicKey(config.tokenProgramId); - } catch (err) { - tokenProgramId = await loadProgram( - connection, - '../../target/bpfel-unknown-unknown/release/spl_token.so', - ); - await store.save('config.json', { - tokenProgramId: tokenProgramId.toString(), - }); - } - return tokenProgramId; -} - -export async function loadTokenProgram(): Promise { - const connection = await getConnection(); - programId = await GetPrograms(connection); - - console.log('Token Program ID', programId.toString()); -} - -export async function createMint(): Promise { - const connection = await getConnection(); - const payer = await newAccountWithLamports( - connection, - 100000000000 /* wag */, - ); - mintOwner = new Account(); - testAccountOwner = new Account(); - [testToken, testAccount] = await Token.createMint( - connection, - payer, - mintOwner.publicKey, - testAccountOwner.publicKey, - new u64(10000), - 2, - programId, - false, - ); - - const mintInfo = await testToken.getMintInfo(); - assert(mintInfo.decimals == 2); - assert(mintInfo.owner == null); - - const accountInfo = await testToken.getAccountInfo(testAccount); - assert(accountInfo.mint.equals(testToken.publicKey)); - assert(accountInfo.owner.equals(testAccountOwner.publicKey)); - assert(accountInfo.amount.toNumber() == 10000); - assert(accountInfo.delegate == null); - assert(accountInfo.delegatedAmount.toNumber() == 0); -} - -export async function createAccount(): Promise { - const destOwner = new Account(); - const account = await testToken.createAccount(destOwner.publicKey); - const accountInfo = await testToken.getAccountInfo(account); - assert(accountInfo.mint.equals(testToken.publicKey)); - assert(accountInfo.owner.equals(destOwner.publicKey)); - assert(accountInfo.amount.toNumber() == 0); - assert(accountInfo.delegate == null); -} - -export async function transfer(): Promise { - const destOwner = new Account(); - const dest = await testToken.createAccount(destOwner.publicKey); - - await testToken.transfer(testAccount, dest, testAccountOwner, [], 123); - await sleep(500); - - let destAccountInfo = await testToken.getAccountInfo(dest); - assert(destAccountInfo.amount.toNumber() == 123); -} - -export async function approveRevoke(): Promise { - if (programId == null) { - console.log('test skipped, requires "load token program" to succeed'); - return; - } - - const delegate = new PublicKey(); - await testToken.approve(testAccount, delegate, testAccountOwner, [], 456); - let testAccountInfo = await testToken.getAccountInfo(testAccount); - assert(testAccountInfo.delegatedAmount.toNumber() == 456); - if (testAccountInfo.delegate === null) { - throw new Error('deleage should not be null'); - } else { - assert(testAccountInfo.delegate.equals(delegate)); - } - - await testToken.revoke(testAccount, testAccountOwner, []); - testAccountInfo = await testToken.getAccountInfo(testAccount); - assert(testAccountInfo.delegatedAmount.toNumber() == 0); - if (testAccountInfo.delegate != null) { - throw new Error('delegate should be null'); - } -} - -export async function invalidApprove(): Promise { - const owner = new Account(); - const account1 = await testToken.createAccount(owner.publicKey); - const account2 = await testToken.createAccount(owner.publicKey); - const delegate = new Account(); - - // account2 is not a delegate account of account1 - assert(didThrow(testToken.approve, [account1, account2, owner, [], 123])); - // account1Delegate is not a delegate account of account2 - assert(didThrow(testToken.approve, [account2, delegate, owner, [], 123])); -} - -export async function failOnApproveOverspend(): Promise { - const owner = new Account(); - const account1 = await testToken.createAccount(owner.publicKey); - const account2 = await testToken.createAccount(owner.publicKey); - const delegate = new Account(); - - await testToken.transfer(testAccount, account1, testAccountOwner, [], 10); - - await testToken.approve(account1, delegate.publicKey, owner, [], 2); - - let account1Info = await testToken.getAccountInfo(account1); - assert(account1Info.amount.toNumber() == 10); - assert(account1Info.delegatedAmount.toNumber() == 2); - if (account1Info.delegate === null) { - throw new Error('deleage should not be null'); - } else { - assert(account1Info.delegate.equals(delegate.publicKey)); - } - - await testToken.transfer(account1, account2, delegate, [], 1); - - account1Info = await testToken.getAccountInfo(account1); - assert(account1Info.amount.toNumber() == 9); - assert(account1Info.delegatedAmount.toNumber() == 1); - - await testToken.transfer(account1, account2, delegate, [], 1); - - account1Info = await testToken.getAccountInfo(account1); - assert(account1Info.amount.toNumber() == 8); - assert(account1Info.delegate === null); - assert(account1Info.delegatedAmount.toNumber() == 0); - - assert(didThrow(testToken.transfer, [account1, account2, delegate, [], 1])); -} - -export async function setOwner(): Promise { - const owner = new Account(); - const newOwner = new Account(); - const owned = await testToken.createAccount(owner.publicKey); - - await testToken.setOwner(owned, newOwner.publicKey, owner, []); - assert(didThrow(testToken.setOwner, [owned, newOwner.publicKey, owner, []])); - await testToken.setOwner(owned, owner.publicKey, newOwner, []); -} - -export async function mintTo(): Promise { - const connection = await getConnection(); - const payer = await newAccountWithLamports( - connection, - 100000000000 /* wag */, - ); - mintableOwner = new Account(); - testMintableAccountOwner = new Account(); - [testMintableToken, testMintableAccount] = await Token.createMint( - connection, - payer, - mintableOwner.publicKey, - testMintableAccountOwner.publicKey, - new u64(10000), - 2, - programId, - true, - ); - - { - const mintInfo = await testMintableToken.getMintInfo(); - assert(mintInfo.decimals == 2); - if (mintInfo.owner === null) { - throw new Error('owner should not be null'); - } else { - assert(mintInfo.owner.equals(mintableOwner.publicKey)); - } - - const accountInfo = await testMintableToken.getAccountInfo( - testMintableAccount, - ); - assert(accountInfo.mint.equals(testMintableToken.publicKey)); - assert(accountInfo.owner.equals(testMintableAccountOwner.publicKey)); - assert(accountInfo.amount.toNumber() == 10000); - assert(accountInfo.delegate == null); - assert(accountInfo.delegatedAmount.toNumber() == 0); - } - - const dest = await testMintableToken.createAccount( - testMintableAccountOwner.publicKey, - ); - await testMintableToken.mintTo(dest, mintableOwner, [], 42); - - { - const mintInfo = await testMintableToken.getMintInfo(); - assert(mintInfo.decimals == 2); - if (mintInfo.owner === null) { - throw new Error('owner should not be null'); - } else { - assert(mintInfo.owner.equals(mintableOwner.publicKey)); - } - - const accountInfo = await testMintableToken.getAccountInfo(dest); - assert(accountInfo.mint.equals(testMintableToken.publicKey)); - assert(accountInfo.owner.equals(testMintableAccountOwner.publicKey)); - assert(accountInfo.amount.toNumber() == 42); - assert(accountInfo.delegate == null); - assert(accountInfo.delegatedAmount.toNumber() == 0); - } -} - -export async function burn(): Promise { - let accountInfo = await testToken.getAccountInfo(testAccount); - const amount = accountInfo.amount.toNumber(); - - await testToken.burn(testAccount, testAccountOwner, [], 1); - await sleep(500); - - accountInfo = await testToken.getAccountInfo(testAccount); - assert(accountInfo.amount.toNumber() == amount - 1); -} - -export async function multisig(): Promise { - const m = 2; - const n = 5; - - let signerAccounts = []; - for (var i = 0; i < n; i++) { - signerAccounts.push(new Account()); - } - let signerPublicKeys = []; - signerAccounts.forEach(account => signerPublicKeys.push(account.publicKey)); - const multisig = await testToken.createMultisig(m, signerPublicKeys); - - const multisigInfo = await testToken.getMultisigInfo(multisig); - assert(multisigInfo.m === m); - assert(multisigInfo.n === n); - assert(multisigInfo.signer1.equals(signerPublicKeys[0])); - assert(multisigInfo.signer2.equals(signerPublicKeys[1])); - assert(multisigInfo.signer3.equals(signerPublicKeys[2])); - assert(multisigInfo.signer4.equals(signerPublicKeys[3])); - assert(multisigInfo.signer5.equals(signerPublicKeys[4])); - - const multisigOwnedAccount = await testToken.createAccount(multisig); - const finalDest = await testToken.createAccount(multisig); - await testToken.transfer( - testAccount, - multisigOwnedAccount, - testAccountOwner, - [], - 2, - ); - - // Transfer via multisig - await testToken.transfer( - multisigOwnedAccount, - finalDest, - multisig, - signerAccounts, - 1, - ); - await sleep(500); - let accountInfo = await testToken.getAccountInfo(finalDest); - assert(accountInfo.amount.toNumber() == 1); - - // Approve via multisig - { - const delegate = new PublicKey(); - await testToken.approve( - multisigOwnedAccount, - delegate, - multisig, - signerAccounts, - 1, - ); - const accountInfo = await testToken.getAccountInfo(multisigOwnedAccount); - assert(accountInfo.delegate != null); - if (accountInfo.delegate != null) { - assert(accountInfo.delegate.equals(delegate)); - assert(accountInfo.delegatedAmount.toNumber() == 1); - } - } - - // MintTo via multisig - { - let accountInfo = await testMintableToken.getAccountInfo( - testMintableAccount, - ); - const initialAmount = accountInfo.amount.toNumber(); - await testMintableToken.setOwner( - testMintableToken.publicKey, - multisig, - mintableOwner, - [], - ); - await testMintableToken.mintTo( - testMintableAccount, - multisig, - signerAccounts, - 42, - ); - accountInfo = await testMintableToken.getAccountInfo(testMintableAccount); - assert(accountInfo.amount.toNumber() == initialAmount + 42); - } - - // SetOwner of mint via multisig - { - await testMintableToken.setOwner( - testMintableToken.publicKey, - mintableOwner.publicKey, - multisig, - signerAccounts, - ); - const mintInfo = await testMintableToken.getMintInfo(); - assert(mintInfo.owner != null); - if (mintInfo.owner != null) { - assert(mintInfo.owner.equals(mintableOwner.publicKey)); - } - } - - // SetOwner of account via multisig - { - const newOwner = new PublicKey(); - await testToken.setOwner( - multisigOwnedAccount, - newOwner, - multisig, - signerAccounts, - ); - const accountInfo = await testToken.getAccountInfo(multisigOwnedAccount); - assert(accountInfo.owner.equals(newOwner)); - } -} - -export async function failOnCloseAccount(): Promise { - const connection = await getConnection(); - const owner = new Account(); - const close = await testToken.createAccount(owner.publicKey); - - let close_balance; - let info = await connection.getAccountInfo(close); - if (info != null) { - close_balance = info.lamports; - } else { - throw new Error('Account not found'); - } - - // Initialize destination account to isolate source of failure - const balanceNeeded = await connection.getMinimumBalanceForRentExemption(0); - const dest = await newAccountWithLamports(connection, balanceNeeded); - - info = await connection.getAccountInfo(dest.publicKey); - if (info != null) { - assert(info.lamports == balanceNeeded); - } else { - throw new Error('Account not found'); - } - - assert(didThrow(testToken.closeAccount, [close, dest.publicKey, owner, []])); - - info = await connection.getAccountInfo(close); - if (info != null) { - assert(info.lamports == close_balance); - } else { - throw new Error('Account not found'); - } -} - -export async function nativeToken(): Promise { - const connection = await getConnection(); - - const mintPublicKey = new PublicKey( - 'So11111111111111111111111111111111111111111', - ); - const payer = await newAccountWithLamports( - connection, - 100000000000 /* wag */, - ); - const token = new Token(connection, mintPublicKey, programId, payer); - const owner = new Account(); - const native = await token.createAccount(owner.publicKey); - let accountInfo = await token.getAccountInfo(native); - assert(accountInfo.isNative); - let balance; - let info = await connection.getAccountInfo(native); - if (info != null) { - balance = info.lamports; - } else { - throw new Error('Account not found'); - } - - const balanceNeeded = await connection.getMinimumBalanceForRentExemption(0); - const dest = await newAccountWithLamports(connection, balanceNeeded); - await token.closeAccount(native, dest.publicKey, owner, []); - info = await connection.getAccountInfo(native); - if (info != null) { - throw new Error('Account not burned'); - } - info = await connection.getAccountInfo(dest.publicKey); - if (info != null) { - assert(info.lamports == balanceNeeded + balance); - } else { - throw new Error('Account not found'); - } -} diff --git a/program/js/client/layout.js b/program/js/client/layout.js deleted file mode 100644 index 6c3e06b..0000000 --- a/program/js/client/layout.js +++ /dev/null @@ -1,47 +0,0 @@ -// @flow - -import * as BufferLayout from 'buffer-layout'; - -/** - * Layout for a public key - */ -export const publicKey = (property: string = 'publicKey'): Object => { - return BufferLayout.blob(32, property); -}; - -/** - * Layout for a 64bit unsigned value - */ -export const uint64 = (property: string = 'uint64'): Object => { - return BufferLayout.blob(8, property); -}; - -/** - * Layout for a Rust String type - */ -export const rustString = (property: string = 'string') => { - const rsl = BufferLayout.struct( - [ - BufferLayout.u32('length'), - BufferLayout.u32('lengthPadding'), - BufferLayout.blob(BufferLayout.offset(BufferLayout.u32(), -8), 'chars'), - ], - property, - ); - const _decode = rsl.decode.bind(rsl); - const _encode = rsl.encode.bind(rsl); - - rsl.decode = (buffer, offset) => { - const data = _decode(buffer, offset); - return data.chars.toString('utf8'); - }; - - rsl.encode = (str, buffer, offset) => { - const data = { - chars: Buffer.from(str, 'utf8'), - }; - return _encode(data, buffer, offset); - }; - - return rsl; -}; diff --git a/program/js/client/token.js b/program/js/client/token.js deleted file mode 100644 index e59a2ab..0000000 --- a/program/js/client/token.js +++ /dev/null @@ -1,1242 +0,0 @@ -/** - * @flow - */ - -import assert from 'assert'; -import BN from 'bn.js'; -import * as BufferLayout from 'buffer-layout'; -import { - Account, - PublicKey, - SystemProgram, - Transaction, - TransactionInstruction, -} from '@solana/web3.js'; -import type {Connection, TransactionSignature} from '@solana/web3.js'; - -import * as Layout from './layout'; -import {sendAndConfirmTransaction} from './util/send-and-confirm-transaction'; - -/** - * 64-bit value - */ -export class u64 extends BN { - /** - * Convert to Buffer representation - */ - toBuffer(): Buffer { - const a = super.toArray().reverse(); - const b = Buffer.from(a); - if (b.length === 8) { - return b; - } - assert(b.length < 8, 'u64 too large'); - - const zeroPad = Buffer.alloc(8); - b.copy(zeroPad); - return zeroPad; - } - - /** - * Construct a u64 from Buffer representation - */ - static fromBuffer(buffer: Buffer): u64 { - assert(buffer.length === 8, `Invalid buffer length: ${buffer.length}`); - return new BN( - [...buffer] - .reverse() - .map(i => `00${i.toString(16)}`.slice(-2)) - .join(''), - 16, - ); - } -} - -function isAccount(accountOrPublicKey: any): boolean { - return 'publicKey' in accountOrPublicKey; -} - -/** - * Information about the mint - */ -type MintInfo = {| - /** - * Owner of the mint, given authority to mint new tokens - */ - owner: null | PublicKey, - - /** - * Number of base 10 digits to the right of the decimal place - */ - decimals: number, - - /** - * Is this mint initialized - */ - initialized: boolean, -|}; - -const MintLayout = BufferLayout.struct([ - BufferLayout.u32('option'), - Layout.publicKey('owner'), - BufferLayout.u8('decimals'), - BufferLayout.u8('is_initialized'), - BufferLayout.u16('padding'), -]); - -/** - * Information about an account - */ -type AccountInfo = {| - /** - * The mint associated with this account - */ - mint: PublicKey, - - /** - * Owner of this account - */ - owner: PublicKey, - - /** - * Amount of tokens this account holds - */ - amount: u64, - - /** - * The delegate for this account - */ - delegate: null | PublicKey, - - /** - * The amount of tokens the delegate authorized to the delegate - */ - delegatedAmount: u64, - - /** - * Is this account initialized - */ - isInitialized: boolean, - - /** - * Is this a native token account - */ - isNative: boolean, -|}; - -/** - * @private - */ -const AccountLayout = BufferLayout.struct([ - Layout.publicKey('mint'), - Layout.publicKey('owner'), - Layout.uint64('amount'), - BufferLayout.u32('option'), - Layout.publicKey('delegate'), - BufferLayout.u8('is_initialized'), - BufferLayout.u8('is_native'), - BufferLayout.u16('padding'), - Layout.uint64('delegatedAmount'), -]); - -/** - * Information about an multisig - */ -type MultisigInfo = {| - /** - * The number of signers required - */ - m: number, - - /** - * Number of possible signers, corresponds to the - * number of `signers` that are valid. - */ - n: number, - - /** - * Is this mint initialized - */ - initialized: boolean, - - /** - * The signers - */ - signer1: PublicKey, - signer2: PublicKey, - signer3: PublicKey, - signer4: PublicKey, - signer5: PublicKey, - signer6: PublicKey, - signer7: PublicKey, - signer8: PublicKey, - signer9: PublicKey, - signer10: PublicKey, - signer11: PublicKey, -|}; - -/** - * @private - */ -const MultisigLayout = BufferLayout.struct([ - BufferLayout.u8('m'), - BufferLayout.u8('n'), - BufferLayout.u8('is_initialized'), - Layout.publicKey('signer1'), - Layout.publicKey('signer2'), - Layout.publicKey('signer3'), - Layout.publicKey('signer4'), - Layout.publicKey('signer5'), - Layout.publicKey('signer6'), - Layout.publicKey('signer7'), - Layout.publicKey('signer8'), - Layout.publicKey('signer9'), - Layout.publicKey('signer10'), - Layout.publicKey('signer11'), -]); - -type TokenAndPublicKey = [Token, PublicKey]; // This type exists to workaround an esdoc parse error - -/** - * An ERC20-like Token - */ -export class Token { - /** - * @private - */ - connection: Connection; - - /** - * The public key identifying this mint - */ - publicKey: PublicKey; - - /** - * Program Identifier for the Token program - */ - programId: PublicKey; - - /** - * Fee payer - */ - payer: Account; - - /** - * Create a Token object attached to the specific mint - * - * @param connection The connection to use - * @param token Public key of the mint - * @param programId token programId - * @param payer Payer of fees - */ - constructor( - connection: Connection, - publicKey: PublicKey, - programId: PublicKey, - payer: Account, - ) { - Object.assign(this, {connection, publicKey, programId, payer}); - } - - /** - * Get the minimum balance for the mint to be rent exempt - * - * @return Number of lamports required - */ - static async getMinBalanceRentForExemptMint( - connection: Connection, - ): Promise { - return await connection.getMinimumBalanceForRentExemption(MintLayout.span); - } - - /** - * Get the minimum balance for the account to be rent exempt - * - * @return Number of lamports required - */ - static async getMinBalanceRentForExemptAccount( - connection: Connection, - ): Promise { - return await connection.getMinimumBalanceForRentExemption( - AccountLayout.span, - ); - } - - /** - * Get the minimum balance for the multsig to be rent exempt - * - * @return Number of lamports required - */ - static async getMinBalanceRentForExemptMultisig( - connection: Connection, - ): Promise { - return await connection.getMinimumBalanceForRentExemption( - MultisigLayout.span, - ); - } - - /** - * Creates and initializes a token. - * - * @param connection The connection to use - * @param owner User account that will own the returned account - * @param supply Initial supply to mint - * @param decimals Location of the decimal place - * @param programId Optional token programId, uses the system programId by default - * @return Token object for the newly minted token, Public key of the account - * holding the total amount of new tokens - */ - static async createMint( - connection: Connection, - payer: Account, - mintOwner: PublicKey, - accountOwner: PublicKey, - supply: u64, - decimals: number, - programId: PublicKey, - is_owned: boolean = false, - ): Promise { - let transaction; - const mintAccount = new Account(); - const token = new Token( - connection, - mintAccount.publicKey, - programId, - payer, - ); - const initialAccountPublicKey = await token.createAccount(accountOwner); - - // Allocate memory for the account - const balanceNeeded = await Token.getMinBalanceRentForExemptMint( - connection, - ); - transaction = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: mintAccount.publicKey, - lamports: balanceNeeded, - space: MintLayout.span, - programId, - }); - - // Create the mint - let keys = [ - {pubkey: mintAccount.publicKey, isSigner: false, isWritable: true}, - ]; - if (supply.toNumber() != 0) { - keys.push({ - pubkey: initialAccountPublicKey, - isSigner: false, - isWritable: true, - }); - } - if (is_owned) { - keys.push({pubkey: mintOwner, isSigner: false, isWritable: false}); - } - const commandDataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('supply'), - BufferLayout.u8('decimals'), - ]); - let data = Buffer.alloc(1024); - { - const encodeLength = commandDataLayout.encode( - { - instruction: 0, // InitializeMint instruction - supply: supply.toBuffer(), - decimals, - }, - data, - ); - data = data.slice(0, encodeLength); - } - transaction.add({ - keys, - programId, - data, - }); - - // Send the two instructions - await sendAndConfirmTransaction( - 'createAccount and InitializeMint', - connection, - transaction, - payer, - mintAccount, - ); - - return [token, initialAccountPublicKey]; - } - - /** - * Create and initializes a new account. - * - * This account may then be used as a `transfer()` or `approve()` destination - * - * @param owner User account that will own the new account - * @return Public key of the new empty account - */ - async createAccount(owner: PublicKey): Promise { - const mintAccount = new Account(); - let transaction; - - // Allocate memory for the account - const balanceNeeded = await Token.getMinBalanceRentForExemptAccount( - this.connection, - ); - transaction = SystemProgram.createAccount({ - fromPubkey: this.payer.publicKey, - newAccountPubkey: mintAccount.publicKey, - lamports: balanceNeeded, - space: AccountLayout.span, - programId: this.programId, - }); - - // create the new account - const keys = [ - {pubkey: mintAccount.publicKey, isSigner: false, isWritable: true}, - {pubkey: this.publicKey, isSigner: false, isWritable: false}, - {pubkey: owner, isSigner: false, isWritable: false}, - ]; - const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]); - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 1, // InitializeAccount instruction - }, - data, - ); - transaction.add({ - keys, - programId: this.programId, - data, - }); - - // Send the two instructions - await sendAndConfirmTransaction( - 'createAccount and InitializeAccount', - this.connection, - transaction, - this.payer, - mintAccount, - ); - - return mintAccount.publicKey; - } - - /** - * Create and initializes a new multisig. - * - * This account may then be used for multisignature verification - * - * @param owner User account that will own the multsig account - * @return Public key of the new multisig account - */ - async createMultisig( - m: number, - signers: Array, - ): Promise { - const multisigAccount = new Account(); - let transaction; - - // Allocate memory for the account - const balanceNeeded = await Token.getMinBalanceRentForExemptMultisig( - this.connection, - ); - transaction = SystemProgram.createAccount({ - fromPubkey: this.payer.publicKey, - newAccountPubkey: multisigAccount.publicKey, - lamports: balanceNeeded, - space: MultisigLayout.span, - programId: this.programId, - }); - - // create the new account - let keys = [ - {pubkey: multisigAccount.publicKey, isSigner: false, isWritable: true}, - ]; - signers.forEach(signer => - keys.push({pubkey: signer, isSigner: false, isWritable: false}), - ); - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - BufferLayout.u8('m'), - ]); - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 2, // InitializeM { - const info = await this.connection.getAccountInfo(this.publicKey); - if (info === null) { - throw new Error('Failed to find mint account'); - } - if (!info.owner.equals(this.programId)) { - throw new Error(`Invalid mint owner: ${JSON.stringify(info.owner)}`); - } - if (info.data.length != MintLayout.span) { - throw new Error(`Invalid mint size`); - } - - const data = Buffer.from(info.data); - const mintInfo = MintLayout.decode(data); - if (mintInfo.option === 0) { - mintInfo.owner = null; - } else { - mintInfo.owner = new PublicKey(mintInfo.owner); - } - return mintInfo; - } - - /** - * Retrieve account information - * - * @param account Public key of the account - */ - async getAccountInfo(account: PublicKey): Promise { - const info = await this.connection.getAccountInfo(account); - if (info === null) { - throw new Error('Failed to find account'); - } - if (!info.owner.equals(this.programId)) { - throw new Error(`Invalid account owner`); - } - if (info.data.length != AccountLayout.span) { - throw new Error(`Invalid account size`); - } - - const data = Buffer.from(info.data); - const accountInfo = AccountLayout.decode(data); - accountInfo.mint = new PublicKey(accountInfo.mint); - accountInfo.owner = new PublicKey(accountInfo.owner); - accountInfo.amount = u64.fromBuffer(accountInfo.amount); - accountInfo.isInitialized = accountInfo.isInitialized != 0; - accountInfo.isNative = accountInfo.isNative != 0; - if (accountInfo.option === 0) { - accountInfo.delegate = null; - accountInfo.delegatedAmount = new u64(); - } else { - accountInfo.delegate = new PublicKey(accountInfo.delegate); - accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount); - } - - if (!accountInfo.mint.equals(this.publicKey)) { - throw new Error( - `Invalid account mint: ${JSON.stringify( - accountInfo.mint, - )} !== ${JSON.stringify(this.publicKey)}`, - ); - } - return accountInfo; - } - - /** - * Retrieve Multisig information - * - * @param multisig Public key of the account - */ - async getMultisigInfo(multisig: PublicKey): Promise { - const info = await this.connection.getAccountInfo(multisig); - if (info === null) { - throw new Error('Failed to find multisig'); - } - if (!info.owner.equals(this.programId)) { - throw new Error(`Invalid multisig owner`); - } - if (info.data.length != MultisigLayout.span) { - throw new Error(`Invalid multisig size`); - } - - const data = Buffer.from(info.data); - const multisigInfo = MultisigLayout.decode(data); - multisigInfo.signer1 = new PublicKey(multisigInfo.signer1); - multisigInfo.signer2 = new PublicKey(multisigInfo.signer2); - multisigInfo.signer3 = new PublicKey(multisigInfo.signer3); - multisigInfo.signer4 = new PublicKey(multisigInfo.signer4); - multisigInfo.signer5 = new PublicKey(multisigInfo.signer5); - multisigInfo.signer6 = new PublicKey(multisigInfo.signer6); - multisigInfo.signer7 = new PublicKey(multisigInfo.signer7); - multisigInfo.signer8 = new PublicKey(multisigInfo.signer8); - multisigInfo.signer9 = new PublicKey(multisigInfo.signer9); - multisigInfo.signer10 = new PublicKey(multisigInfo.signer10); - multisigInfo.signer11 = new PublicKey(multisigInfo.signer11); - - return multisigInfo; - } - - /** - * Transfer tokens to another account - * - * @param source Source account - * @param destination Destination account - * @param authority Owner of the source account - * @param multiSigners Signing accounts if `authority` is a multiSig - * @param amount Number of tokens to transfer - */ - async transfer( - source: PublicKey, - destination: PublicKey, - authority: any, - multiSigners: Array, - amount: number | u64, - ): Promise { - let ownerPublicKey; - let signers; - if (isAccount(authority)) { - ownerPublicKey = authority.publicKey; - signers = [authority]; - } else { - ownerPublicKey = authority; - signers = multiSigners; - } - return await sendAndConfirmTransaction( - 'Transfer', - this.connection, - new Transaction().add( - Token.createTransferInstruction( - this.programId, - source, - destination, - ownerPublicKey, - multiSigners, - amount, - ), - ), - this.payer, - ...signers, - ); - } - - /** - * Grant a third-party permission to transfer up the specified number of tokens from an account - * - * @param account Public key of the account - * @param delegate Account authorized to perform a transfer tokens from the source account - * @param owner Owner of the source account - * @param multiSigners Signing accounts if `owner` is a multiSig - * @param amount Maximum number of tokens the delegate may transfer - */ - async approve( - account: PublicKey, - delegate: PublicKey, - owner: any, - multiSigners: Array, - amount: number | u64, - ): Promise { - let ownerPublicKey; - let signers; - if (isAccount(owner)) { - ownerPublicKey = owner.publicKey; - signers = [owner]; - } else { - ownerPublicKey = owner; - signers = multiSigners; - } - await sendAndConfirmTransaction( - 'Approve', - this.connection, - new Transaction().add( - Token.createApproveInstruction( - this.programId, - account, - delegate, - ownerPublicKey, - multiSigners, - amount, - ), - ), - this.payer, - ...signers, - ); - } - - /** - * Remove approval for the transfer of any remaining tokens - * - * @param account Public key of the account - * @param owner Owner of the source account - * @param multiSigners Signing accounts if `owner` is a multiSig - */ - async revoke( - account: PublicKey, - owner: any, - multiSigners: Array, - ): Promise { - let ownerPublicKey; - let signers; - if (isAccount(owner)) { - ownerPublicKey = owner.publicKey; - signers = [owner]; - } else { - ownerPublicKey = owner; - signers = multiSigners; - } - await sendAndConfirmTransaction( - 'Revoke', - this.connection, - new Transaction().add( - Token.createRevokeInstruction( - this.programId, - account, - ownerPublicKey, - multiSigners, - ), - ), - this.payer, - ...signers, - ); - } - - /** - * Assign a new owner to the account - * - * @param account Public key of the account - * @param newOwner New owner of the account - * @param owner Owner of the account - * @param multiSigners Signing accounts if `owner` is a multiSig - */ - async setOwner( - owned: PublicKey, - newOwner: PublicKey, - owner: any, - multiSigners: Array, - ): Promise { - let ownerPublicKey; - let signers; - if (isAccount(owner)) { - ownerPublicKey = owner.publicKey; - signers = [owner]; - } else { - ownerPublicKey = owner; - signers = multiSigners; - } - await sendAndConfirmTransaction( - 'SetOwner', - this.connection, - new Transaction().add( - Token.createSetOwnerInstruction( - this.programId, - owned, - newOwner, - ownerPublicKey, - multiSigners, - ), - ), - this.payer, - ...signers, - ); - } - - /** - * Mint new tokens - * - * @param mint Public key of the mint - * @param dest Public key of the account to mint to - * @param authority Owner of the mint - * @param multiSigners Signing accounts if `authority` is a multiSig - * @param amount ammount to mint - */ - async mintTo( - dest: PublicKey, - authority: any, - multiSigners: Array, - amount: number, - ): Promise { - let ownerPublicKey; - let signers; - if (isAccount(authority)) { - ownerPublicKey = authority.publicKey; - signers = [authority]; - } else { - ownerPublicKey = authority; - signers = multiSigners; - } - await sendAndConfirmTransaction( - 'MintTo', - this.connection, - new Transaction().add( - Token.createMintToInstruction( - this.programId, - this.publicKey, - dest, - ownerPublicKey, - multiSigners, - amount, - ), - ), - this.payer, - ...signers, - ); - } - - /** - * Burn tokens - * - * @param account Account to burn tokens from - * @param authority Public key account owner - * @param multiSigners Signing accounts if `authority` is a multiSig - * @param amount ammount to burn - */ - async burn( - account: PublicKey, - authority: any, - multiSigners: Array, - amount: number, - ): Promise { - let ownerPublicKey; - let signers; - if (isAccount(authority)) { - ownerPublicKey = authority.publicKey; - signers = [authority]; - } else { - ownerPublicKey = authority; - signers = multiSigners; - } - await sendAndConfirmTransaction( - 'Burn', - this.connection, - new Transaction().add( - Token.createBurnInstruction( - this.programId, - account, - ownerPublicKey, - multiSigners, - amount, - ), - ), - this.payer, - ...signers, - ); - } - - /** - * Burn account - * - * @param account Account to burn - * @param authority account owner - * @param multiSigners Signing accounts if `owner` is a multiSig - */ - async closeAccount( - account: PublicKey, - dest: PublicKey, - owner: any, - multiSigners: Array, - ): Promise { - let ownerPublicKey; - let signers; - if (isAccount(owner)) { - ownerPublicKey = owner.publicKey; - signers = [owner]; - } else { - ownerPublicKey = owner; - signers = multiSigners; - } - await sendAndConfirmTransaction( - 'CloseAccount', - this.connection, - new Transaction().add( - Token.createCloseAccountInstruction( - this.programId, - account, - dest, - ownerPublicKey, - multiSigners, - ), - ), - this.payer, - ...signers, - ); - } - - /** - * Construct a Transfer instruction - * - * @param source Source account - * @param destination Destination account - * @param authority Owner of the source account - * @param multiSigners Signing accounts if `authority` is a multiSig - * @param amount Number of tokens to transfer - */ - static createTransferInstruction( - programId: PublicKey, - source: PublicKey, - destination: PublicKey, - authority: any, - multiSigners: Array, - amount: number | u64, - ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('amount'), - ]); - - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 3, // Transfer instruction - amount: new u64(amount).toBuffer(), - }, - data, - ); - - let keys = [ - {pubkey: source, isSigner: false, isWritable: true}, - {pubkey: destination, isSigner: false, isWritable: true}, - ]; - if (isAccount(authority)) { - keys.push({ - pubkey: authority.publicKey, - isSigner: true, - isWritable: false, - }); - } else { - keys.push({pubkey: authority, isSigner: false, isWritable: false}); - multiSigners.forEach(signer => - keys.push({ - pubkey: signer.publicKey, - isSigner: true, - isWritable: false, - }), - ); - } - return new TransactionInstruction({ - keys, - programId: programId, - data, - }); - } - - /** - * Construct an Approve instruction - * - * @param account Public key of the account - * @param delegate Account authorized to perform a transfer of tokens from the source account - * @param owner Owner of the source account - * @param multiSigners Signing accounts if `owner` is a multiSig - * @param amount Maximum number of tokens the delegate may transfer - */ - static createApproveInstruction( - programId: PublicKey, - account: PublicKey, - delegate: PublicKey, - owner: any, - multiSigners: Array, - amount: number | u64, - ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('amount'), - ]); - - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 4, // Approve instruction - amount: new u64(amount).toBuffer(), - }, - data, - ); - - let keys = [ - {pubkey: account, isSigner: false, isWritable: true}, - {pubkey: delegate, isSigner: false, isWritable: false}, - ]; - if (isAccount(owner)) { - keys.push({pubkey: owner.publicKey, isSigner: true, isWritable: false}); - } else { - keys.push({pubkey: owner, isSigner: false, isWritable: false}); - multiSigners.forEach(signer => - keys.push({ - pubkey: signer.publicKey, - isSigner: true, - isWritable: false, - }), - ); - } - - return new TransactionInstruction({ - keys, - programId: programId, - data, - }); - } - - /** - * Construct an Approve instruction - * - * @param account Public key of the account - * @param delegate Account authorized to perform a transfer of tokens from the source account - * @param owner Owner of the source account - * @param multiSigners Signing accounts if `owner` is a multiSig - * @param amount Maximum number of tokens the delegate may transfer - */ - static createRevokeInstruction( - programId: PublicKey, - account: PublicKey, - owner: any, - multiSigners: Array, - ): TransactionInstruction { - const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]); - - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 5, // Approve instruction - }, - data, - ); - - let keys = [{pubkey: account, isSigner: false, isWritable: true}]; - if (isAccount(owner)) { - keys.push({pubkey: owner.publicKey, isSigner: true, isWritable: false}); - } else { - keys.push({pubkey: owner, isSigner: false, isWritable: false}); - multiSigners.forEach(signer => - keys.push({ - pubkey: signer.publicKey, - isSigner: true, - isWritable: false, - }), - ); - } - - return new TransactionInstruction({ - keys, - programId: programId, - data, - }); - } - - /** - * Construct a SetOwner instruction - * - * @param account Public key of the account - * @param newOwner New owner of the account - * @param owner Owner of the account - * @param multiSigners Signing accounts if `owner` is a multiSig - */ - static createSetOwnerInstruction( - programId: PublicKey, - owned: PublicKey, - newOwner: PublicKey, - owner: any, - multiSigners: Array, - ): TransactionInstruction { - const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]); - - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 6, // SetOwner instruction - }, - data, - ); - - let keys = [ - {pubkey: owned, isSigner: false, isWritable: true}, - {pubkey: newOwner, isSigner: false, isWritable: false}, - ]; - if (isAccount(owner)) { - keys.push({pubkey: owner.publicKey, isSigner: true, isWritable: false}); - } else { - keys.push({pubkey: owner, isSigner: false, isWritable: false}); - multiSigners.forEach(signer => - keys.push({ - pubkey: signer.publicKey, - isSigner: true, - isWritable: false, - }), - ); - } - - return new TransactionInstruction({ - keys, - programId: programId, - data, - }); - } - - /** - * Construct a MintTo instruction - * - * @param dest Public key of the account to mint to - * @param authority Owner of the mint - * @param multiSigners Signing accounts if `authority` is a multiSig - - * @param amount amount to mint - */ - static createMintToInstruction( - programId: PublicKey, - mint: PublicKey, - dest: PublicKey, - authority: any, - multiSigners: Array, - amount: number, - ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('amount'), - ]); - - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 7, // MintTo instruction - amount: new u64(amount).toBuffer(), - }, - data, - ); - - let keys = [ - {pubkey: mint, isSigner: false, isWritable: true}, - {pubkey: dest, isSigner: false, isWritable: true}, - ]; - if (isAccount(authority)) { - keys.push({ - pubkey: authority.publicKey, - isSigner: true, - isWritable: false, - }); - } else { - keys.push({pubkey: authority, isSigner: false, isWritable: false}); - multiSigners.forEach(signer => - keys.push({ - pubkey: signer.publicKey, - isSigner: true, - isWritable: false, - }), - ); - } - - return new TransactionInstruction({ - keys, - programId: programId, - data, - }); - } - - /** - * Construct a Burn instruction - * - * @param account Account to burn tokens from - * @param authority Public key account owner - * @param multiSigners Signing accounts if `authority` is a multiSig - * @param amount ammount to burn - */ - static createBurnInstruction( - programId: PublicKey, - account: PublicKey, - authority: any, - multiSigners: Array, - amount: number, - ): TransactionInstruction { - const dataLayout = BufferLayout.struct([ - BufferLayout.u8('instruction'), - Layout.uint64('amount'), - ]); - - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 8, // Burn instruction - amount: new u64(amount).toBuffer(), - }, - data, - ); - - let keys = [{pubkey: account, isSigner: false, isWritable: true}]; - if (isAccount(authority)) { - keys.push({ - pubkey: authority.publicKey, - isSigner: true, - isWritable: false, - }); - } else { - keys.push({pubkey: authority, isSigner: false, isWritable: false}); - multiSigners.forEach(signer => - keys.push({ - pubkey: signer.publicKey, - isSigner: true, - isWritable: false, - }), - ); - } - - return new TransactionInstruction({ - keys, - programId: programId, - data, - }); - } - - /** - * Construct a Burn instruction - * - * @param account Account to burn tokens from - * @param owner account owner - * @param multiSigners Signing accounts if `owner` is a multiSig - */ - static createCloseAccountInstruction( - programId: PublicKey, - account: PublicKey, - dest: PublicKey, - owner: any, - multiSigners: Array, - ): TransactionInstruction { - const dataLayout = BufferLayout.struct([BufferLayout.u8('instruction')]); - const data = Buffer.alloc(dataLayout.span); - dataLayout.encode( - { - instruction: 9, // CloseAccount instruction - }, - data, - ); - - let keys = [ - {pubkey: account, isSigner: false, isWritable: true}, - {pubkey: dest, isSigner: false, isWritable: true}, - ]; - if (isAccount(owner)) { - keys.push({pubkey: owner.publicKey, isSigner: true, isWritable: false}); - } else { - keys.push({pubkey: owner, isSigner: false, isWritable: false}); - multiSigners.forEach(signer => - keys.push({ - pubkey: signer.publicKey, - isSigner: true, - isWritable: false, - }), - ); - } - - return new TransactionInstruction({ - keys, - programId: programId, - data, - }); - } -} diff --git a/program/js/client/util/new-account-with-lamports.js b/program/js/client/util/new-account-with-lamports.js deleted file mode 100644 index 423972f..0000000 --- a/program/js/client/util/new-account-with-lamports.js +++ /dev/null @@ -1,25 +0,0 @@ -// @flow - -import {Account, Connection} from '@solana/web3.js'; - -import {sleep} from './sleep'; - -export async function newAccountWithLamports( - connection: Connection, - lamports: number = 1000000, -): Promise { - const account = new Account(); - - let retries = 30; - await connection.requestAirdrop(account.publicKey, lamports); - for (;;) { - await sleep(500); - if (lamports == (await connection.getBalance(account.publicKey))) { - return account; - } - if (--retries <= 0) { - break; - } - } - throw new Error(`Airdrop of ${lamports} failed`); -} diff --git a/program/js/client/util/new-system-account-with-airdrop.js b/program/js/client/util/new-system-account-with-airdrop.js deleted file mode 100644 index 2df5779..0000000 --- a/program/js/client/util/new-system-account-with-airdrop.js +++ /dev/null @@ -1,17 +0,0 @@ -// @flow - -import {Account, Connection} from '@solana/web3.js'; - -/** - * Create a new system account and airdrop it some lamports - * - * @private - */ -export async function newSystemAccountWithAirdrop( - connection: Connection, - lamports: number = 1, -): Promise { - const account = new Account(); - await connection.requestAirdrop(account.publicKey, lamports); - return account; -} diff --git a/program/js/client/util/send-and-confirm-transaction.js b/program/js/client/util/send-and-confirm-transaction.js deleted file mode 100644 index 1088c55..0000000 --- a/program/js/client/util/send-and-confirm-transaction.js +++ /dev/null @@ -1,21 +0,0 @@ -// @flow - -import {sendAndConfirmTransaction as realSendAndConfirmTransaction} from '@solana/web3.js'; -import type { - Account, - Connection, - Transaction, - TransactionSignature, -} from '@solana/web3.js'; - -export function sendAndConfirmTransaction( - title: string, - connection: Connection, - transaction: Transaction, - ...signers: Array -): Promise { - return realSendAndConfirmTransaction(connection, transaction, signers, { - confirmations: 1, - skipPreflight: true, - }); -} diff --git a/program/js/client/util/sleep.js b/program/js/client/util/sleep.js deleted file mode 100644 index 961d48c..0000000 --- a/program/js/client/util/sleep.js +++ /dev/null @@ -1,6 +0,0 @@ -// @flow - -// zzz -export function sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); -} diff --git a/program/js/client/util/store.js b/program/js/client/util/store.js deleted file mode 100644 index fdafb9d..0000000 --- a/program/js/client/util/store.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Simple file-based datastore - * - * @flow - */ - -import path from 'path'; -import fs from 'mz/fs'; -import mkdirp from 'mkdirp-promise'; - -export class Store { - dir = path.join(__dirname, 'store'); - - async load(uri: string): Promise { - const filename = path.join(this.dir, uri); - const data = await fs.readFile(filename, 'utf8'); - const config = JSON.parse(data); - return config; - } - - async save(uri: string, config: Object): Promise { - await mkdirp(this.dir); - const filename = path.join(this.dir, uri); - await fs.writeFile(filename, JSON.stringify(config), 'utf8'); - } -} diff --git a/program/js/cluster-devnet.env b/program/js/cluster-devnet.env deleted file mode 100644 index eccad41..0000000 --- a/program/js/cluster-devnet.env +++ /dev/null @@ -1,2 +0,0 @@ -LIVE=1 -CLUSTER=devnet diff --git a/program/js/cluster-mainnet-beta.env b/program/js/cluster-mainnet-beta.env deleted file mode 100644 index 17239e5..0000000 --- a/program/js/cluster-mainnet-beta.env +++ /dev/null @@ -1,2 +0,0 @@ -LIVE=1 -CLUSTER=mainnet-beta diff --git a/program/js/cluster-testnet.env b/program/js/cluster-testnet.env deleted file mode 100644 index 9bcfb25..0000000 --- a/program/js/cluster-testnet.env +++ /dev/null @@ -1,2 +0,0 @@ -LIVE=1 -CLUSTER=testnet diff --git a/program/js/flow-typed/bn.js.js b/program/js/flow-typed/bn.js.js deleted file mode 100644 index 5412142..0000000 --- a/program/js/flow-typed/bn.js.js +++ /dev/null @@ -1,4 +0,0 @@ -declare module 'bn.js' { - // TODO: Fill in types - declare module.exports: any; -} diff --git a/program/js/flow-typed/bs58.js b/program/js/flow-typed/bs58.js deleted file mode 100644 index 9223fad..0000000 --- a/program/js/flow-typed/bs58.js +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'bs58' { - declare module.exports: { - encode(input: Buffer): string; - decode(input: string): Buffer; - }; -} diff --git a/program/js/flow-typed/buffer-layout.js b/program/js/flow-typed/buffer-layout.js deleted file mode 100644 index 9dd66fe..0000000 --- a/program/js/flow-typed/buffer-layout.js +++ /dev/null @@ -1,4 +0,0 @@ -declare module 'buffer-layout' { - // TODO: Fill in types - declare module.exports: any; -} diff --git a/program/js/flow-typed/mkdirp-promise_vx.x.x.js b/program/js/flow-typed/mkdirp-promise_vx.x.x.js deleted file mode 100644 index 35bb720..0000000 --- a/program/js/flow-typed/mkdirp-promise_vx.x.x.js +++ /dev/null @@ -1,32 +0,0 @@ -// flow-typed signature: 65e18196703cbb222ea294226e99826d -// flow-typed version: <>/mkdirp-promise_v5.0.1/flow_v0.84.0 - -/** - * This is an autogenerated libdef stub for: - * - * 'mkdirp-promise' - * - * Fill this stub out by replacing all the `any` types. - * - * Once filled out, we encourage you to share your work with the - * community by sending a pull request to: - * https://github.com/flowtype/flow-typed - */ - -declare module 'mkdirp-promise' { - declare module.exports: any; -} - -/** - * We include stubs for each file inside this npm package in case you need to - * require those files directly. Feel free to delete any files that aren't - * needed. - */ -declare module 'mkdirp-promise/lib/index' { - declare module.exports: any; -} - -// Filename aliases -declare module 'mkdirp-promise/lib/index.js' { - declare module.exports: $Exports<'mkdirp-promise/lib/index'>; -} diff --git a/program/js/flow-typed/npm/mz_vx.x.x.js b/program/js/flow-typed/npm/mz_vx.x.x.js deleted file mode 100644 index b4b12f4..0000000 --- a/program/js/flow-typed/npm/mz_vx.x.x.js +++ /dev/null @@ -1,73 +0,0 @@ -// flow-typed signature: ed29f42bf4f4916e4f3ba1f5e7343c9d -// flow-typed version: <>/mz_v2.7.0/flow_v0.81.0 - -/** - * This is an autogenerated libdef stub for: - * - * 'mz' - * - * Fill this stub out by replacing all the `any` types. - * - * Once filled out, we encourage you to share your work with the - * community by sending a pull request to: - * https://github.com/flowtype/flow-typed - */ - -declare module 'mz' { - declare module.exports: any; -} - -/** - * We include stubs for each file inside this npm package in case you need to - * require those files directly. Feel free to delete any files that aren't - * needed. - */ -declare module 'mz/child_process' { - declare module.exports: any; -} - -declare module 'mz/crypto' { - declare module.exports: any; -} - -declare module 'mz/dns' { - declare module.exports: any; -} - -declare module 'mz/fs' { - declare module.exports: any; -} - -declare module 'mz/readline' { - declare module.exports: any; -} - -declare module 'mz/zlib' { - declare module.exports: any; -} - -// Filename aliases -declare module 'mz/child_process.js' { - declare module.exports: $Exports<'mz/child_process'>; -} -declare module 'mz/crypto.js' { - declare module.exports: $Exports<'mz/crypto'>; -} -declare module 'mz/dns.js' { - declare module.exports: $Exports<'mz/dns'>; -} -declare module 'mz/fs.js' { - declare module.exports: $Exports<'mz/fs'>; -} -declare module 'mz/index' { - declare module.exports: $Exports<'mz'>; -} -declare module 'mz/index.js' { - declare module.exports: $Exports<'mz'>; -} -declare module 'mz/readline.js' { - declare module.exports: $Exports<'mz/readline'>; -} -declare module 'mz/zlib.js' { - declare module.exports: $Exports<'mz/zlib'>; -} diff --git a/program/js/flow-typed/semver.js b/program/js/flow-typed/semver.js deleted file mode 100644 index 3d6c800..0000000 --- a/program/js/flow-typed/semver.js +++ /dev/null @@ -1,3 +0,0 @@ -declare module 'semver' { - declare module.exports: any; -} diff --git a/program/js/module.d.ts b/program/js/module.d.ts deleted file mode 100644 index 4295bad..0000000 --- a/program/js/module.d.ts +++ /dev/null @@ -1,160 +0,0 @@ -declare module '@solana/spl-token' { - import {Buffer} from 'buffer'; - import { PublicKey, TransactionInstruction, TransactionSignature, Connection } from "@solana/web3.js"; - import BN from 'bn.js'; - - // === client/token.js === - export class u64 extends BN { - toBuffer(): Buffer; - static fromBuffer(buffer: Buffer): u64; - } - export type MintInfo = { - owner: null | PublicKey, - decimals: number, - initialized: boolean, - }; - export type AccountInfo = { - mint: PublicKey, - owner: PublicKey, - amount: u64, - delegate: null | PublicKey, - delegatedAmount: u64, - isInitialized: boolean, - isNative: boolean, - }; - export type MultisigInfo = { - m: number, - n: number, - initialized: boolean, - signer1: PublicKey, - signer2: PublicKey, - signer3: PublicKey, - signer4: PublicKey, - signer5: PublicKey, - signer6: PublicKey, - signer7: PublicKey, - signer8: PublicKey, - signer9: PublicKey, - signer10: PublicKey, - signer11: PublicKey, - }; - export type TokenAndPublicKey = [Token, PublicKey]; - export class Token { - constructor( - connection: Connection, - publicKey: PublicKey, - programId: PublicKey, - payer: Account, - ); - static createMint( - connection: Connection, - payer: Account, - mintOwner: PublicKey, - accountOwner: PublicKey, - supply: u64, - decimals: number, - programId: PublicKey, - is_owned: boolean, - ): Promise; - static getAccount(connection: Connection): Promise; - createAccount(owner: PublicKey): Promise; - createMultisig(m: number, signers: Array): Promise; - getMintInfo(): Promise; - getAccountInfo(account: PublicKey): Promise; - getMultisigInfo(multisig: PublicKey): Promise; - transfer( - source: PublicKey, - destination: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number | u64, - ): Promise; - approve( - account: PublicKey, - delegate: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - amount: number | u64, - ): Promise; - revoke( - account: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): Promise; - setOwner( - owned: PublicKey, - newOwner: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): Promise; - mintTo( - dest: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number, - ): Promise; - burn( - account: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number, - ): Promise; - closeAccount( - account: PublicKey, - dest: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): Promise; - static createTransferInstruction( - programId: PublicKey, - source: PublicKey, - destination: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number | u64, - ): TransactionInstruction; - static createApproveInstruction( - programId: PublicKey, - account: PublicKey, - delegate: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - amount: number | u64, - ): TransactionInstruction; - static createRevokeInstruction( - programId: PublicKey, - account: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): TransactionInstruction; - static createSetOwnerInstruction( - programId: PublicKey, - owned: PublicKey, - newOwner: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): TransactionInstruction; - static createMintToInstruction( - programId: PublicKey, - mint: PublicKey, - dest: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number, - ): TransactionInstruction; - static createBurnInstruction( - programId: PublicKey, - account: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number, - ): TransactionInstruction; - static createCloseAccountInstruction( - programId: PublicKey, - account: PublicKey, - dest: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): TransactionInstruction; - } -} diff --git a/program/js/module.flow.js b/program/js/module.flow.js deleted file mode 100644 index 1d81229..0000000 --- a/program/js/module.flow.js +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Flow Library definition for spl-token - * - * This file is manually maintained - * - */ - -declare module '@solana/spl-token' { - // === client/token.js === - declare export class u64 extends BN { - toBuffer(): Buffer; - static fromBuffer(buffer: Buffer): u64; - } - declare export type MintInfo = {| - owner: null | PublicKey, - decimals: number, - initialized: boolean, - |}; - declare export type AccountInfo = {| - mint: PublicKey, - owner: PublicKey, - amount: u64, - delegate: null | PublicKey, - delegatedAmount: u64, - isInitialized: boolean, - isNative: boolean, - |}; - declare export type MultisigInfo = {| - m: number, - n: number, - initialized: boolean, - signer1: PublicKey, - signer2: PublicKey, - signer3: PublicKey, - signer4: PublicKey, - signer5: PublicKey, - signer6: PublicKey, - signer7: PublicKey, - signer8: PublicKey, - signer9: PublicKey, - signer10: PublicKey, - signer11: PublicKey, - |}; - declare export type TokenAndPublicKey = [Token, PublicKey]; - declare export class Token { - constructor( - connection: Connection, - publicKey: PublicKey, - programId: PublicKey, - payer: Account, - ): Token; - static createMint( - connection: Connection, - payer: Account, - mintOwner: PublicKey, - accountOwner: PublicKey, - supply: u64, - decimals: number, - programId: PublicKey, - is_owned: boolean, - ): Promise; - static getAccount(connection: Connection): Promise; - createAccount(owner: PublicKey): Promise; - createMultisig(m: number, signers: Array): Promise; - getMintInfo(): Promise; - getAccountInfo(account: PublicKey): Promise; - getMultisigInfo(multisig: PublicKey): Promise; - transfer( - source: PublicKey, - destination: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number | u64, - ): Promise; - approve( - account: PublicKey, - delegate: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - amount: number | u64, - ): Promise; - revoke( - account: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): Promise; - setOwner( - owned: PublicKey, - newOwner: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): Promise; - mintTo( - dest: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number, - ): Promise; - burn( - account: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number, - ): Promise; - closeAccount( - account: PublicKey, - dest: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): Promise; - static createTransferInstruction( - programId: PublicKey, - source: PublicKey, - destination: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number | u64, - ): TransactionInstruction; - static createApproveInstruction( - programId: PublicKey, - account: PublicKey, - delegate: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - amount: number | u64, - ): TransactionInstruction; - static createRevokeInstruction( - programId: PublicKey, - account: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): TransactionInstruction; - static createSetOwnerInstruction( - programId: PublicKey, - owned: PublicKey, - newOwner: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): TransactionInstruction; - static createMintToInstruction( - programId: PublicKey, - mint: PublicKey, - dest: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number, - ): TransactionInstruction; - static createBurnInstruction( - programId: PublicKey, - account: PublicKey, - authority: Account | PublicKey, - multiSigners: Array, - amount: number, - ): TransactionInstruction; - static createCloseAccountInstruction( - programId: PublicKey, - account: PublicKey, - dest: PublicKey, - owner: Account | PublicKey, - multiSigners: Array, - ): TransactionInstructio; - } -} diff --git a/program/js/package-lock.json b/program/js/package-lock.json deleted file mode 100644 index 91be906..0000000 --- a/program/js/package-lock.json +++ /dev/null @@ -1,8383 +0,0 @@ -{ - "name": "@solana/spl-token", - "version": "0.0.5", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "101": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/101/-/101-1.6.3.tgz", - "integrity": "sha512-4dmQ45yY0Dx24Qxp+zAsNLlMF6tteCyfVzgbulvSyC7tCyd3V8sW76sS0tHq8NpcbXfWTKasfyfzU1Kd86oKzw==", - "requires": { - "clone": "^1.0.2", - "deep-eql": "^0.1.3", - "keypather": "^1.10.2" - } - }, - "@babel/cli": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.10.5.tgz", - "integrity": "sha512-j9H9qSf3kLdM0Ao3aGPbGZ73mEA9XazuupcS6cDGWuiyAcANoguhP0r2Lx32H5JGw4sSSoHG3x/mxVnHgvOoyA==", - "dev": true, - "requires": { - "chokidar": "^2.1.8", - "commander": "^4.0.1", - "convert-source-map": "^1.1.0", - "fs-readdir-recursive": "^1.1.0", - "glob": "^7.0.0", - "lodash": "^4.17.19", - "make-dir": "^2.1.0", - "slash": "^2.0.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "optional": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "optional": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "optional": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/compat-data": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz", - "integrity": "sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==", - "dev": true, - "requires": { - "browserslist": "^4.12.0", - "invariant": "^2.2.4", - "semver": "^5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "@babel/core": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz", - "integrity": "sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.0", - "@babel/helper-module-transforms": "^7.11.0", - "@babel/helpers": "^7.10.4", - "@babel/parser": "^7.11.1", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.11.0", - "@babel/types": "^7.11.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", - "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", - "dev": true, - "requires": { - "@babel/types": "^7.11.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-module-transforms": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", - "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/template": "^7.10.4", - "@babel/types": "^7.11.0", - "lodash": "^4.17.19" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", - "dev": true, - "requires": { - "@babel/types": "^7.11.0" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.1.tgz", - "integrity": "sha512-u9QMIRdKVF7hfEkb3nu2LgZDIzCQPv+yHD9Eg6ruoJLjkrQ9fFz4IBSlF/9XwoNri9+2F1IY+dYuOfZrXq8t3w==", - "dev": true - }, - "@babel/traverse": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", - "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.0", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.11.0", - "@babel/types": "^7.11.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", - "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.5.tgz", - "integrity": "sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig==", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", - "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", - "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.10.4", - "browserslist": "^4.12.0", - "invariant": "^2.2.4", - "levenary": "^1.1.1", - "semver": "^5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", - "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.10.5", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", - "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-regex": "^7.10.4", - "regexpu-core": "^4.7.0" - } - }, - "@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", - "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz", - "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==", - "dev": true, - "requires": { - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", - "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.5.tgz", - "integrity": "sha512-HiqJpYD5+WopCXIAbQDG0zye5XYVvcO9w/DHp5GsaGkRUaamLj2bEtu6i8rnGGprAhHM3qidCMgp71HF4endhA==", - "dev": true, - "requires": { - "@babel/types": "^7.10.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", - "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } - } - }, - "@babel/helper-module-imports": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", - "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", - "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } - } - }, - "@babel/helper-module-transforms": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.5.tgz", - "integrity": "sha512-4P+CWMJ6/j1W915ITJaUkadLObmCRRSC234uctJfn/vHrsLNxsR8dwlcXv9ZhJWzl77awf+mWXSZEKt5t0OnlA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", - "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", - "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", - "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", - "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", - "dev": true - }, - "@babel/helper-regex": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", - "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz", - "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-replace-supers": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", - "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.5.tgz", - "integrity": "sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig==", - "dev": true, - "requires": { - "@babel/types": "^7.10.5", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", - "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", - "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.5.tgz", - "integrity": "sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", - "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } - } - }, - "@babel/helper-simple-access": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", - "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", - "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", - "dev": true - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", - "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz", - "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==", - "dev": true, - "requires": { - "@babel/types": "^7.11.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", - "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", - "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", - "dev": true, - "requires": { - "@babel/types": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", - "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/helpers": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", - "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" - } - }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/node": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/node/-/node-7.10.5.tgz", - "integrity": "sha512-suosS7zZ2roj+fYVCnDuVezUbRc0sdoyF0Gj/1FzWxD4ebbGiBGtL5qyqHH4NO34B5m4vWWYWgyNhSsrqS8vwA==", - "dev": true, - "requires": { - "@babel/register": "^7.10.5", - "commander": "^4.0.1", - "core-js": "^3.2.1", - "lodash": "^4.17.19", - "node-environment-flags": "^1.0.5", - "regenerator-runtime": "^0.13.4", - "resolve": "^1.13.1", - "v8flags": "^3.1.1" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - }, - "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", - "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } - } - }, - "@babel/parser": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", - "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", - "dev": true - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", - "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", - "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", - "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz", - "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", - "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz", - "integrity": "sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", - "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", - "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", - "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.10.4" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", - "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz", - "integrity": "sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", - "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", - "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", - "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-flow": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.10.4.tgz", - "integrity": "sha512-yxQsX1dJixF4qEEdzVbst3SZQ58Nrooz8NV9Z9GL4byTE25BvJgl5lf0RECUf0fh28rZBb/RYTWn/eeKwCMrZQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", - "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", - "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", - "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.10.4" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", - "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz", - "integrity": "sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", - "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", - "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", - "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", - "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", - "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", - "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.10.4.tgz", - "integrity": "sha512-XTadyuqNst88UWBTdLjM+wEY7BFnY2sYtPyAidfC7M/QaZnSuIZpMvLxqGT7phAcnGyWh/XQFLKcGf04CnvxSQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-flow": "^7.10.4" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", - "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", - "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", - "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", - "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", - "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", - "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", - "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.10.5", - "@babel/helper-plugin-utils": "^7.10.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", - "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", - "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", - "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", - "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.10.4" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", - "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", - "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", - "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", - "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz", - "integrity": "sha512-LFEsP+t3wkYBlis8w6/kmnd6Kb1dxTd+wGJ8MlxTGzQo//ehtqlVL4S9DNUa53+dtPSQobN2CXx4d81FqC58cw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "resolve": "^1.8.1", - "semver": "^5.5.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", - "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz", - "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", - "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-regex": "^7.10.4" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", - "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", - "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", - "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", - "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/preset-env": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.0.tgz", - "integrity": "sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.11.0", - "@babel/helper-compilation-targets": "^7.10.4", - "@babel/helper-module-imports": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-proposal-async-generator-functions": "^7.10.4", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-dynamic-import": "^7.10.4", - "@babel/plugin-proposal-export-namespace-from": "^7.10.4", - "@babel/plugin-proposal-json-strings": "^7.10.4", - "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", - "@babel/plugin-proposal-numeric-separator": "^7.10.4", - "@babel/plugin-proposal-object-rest-spread": "^7.11.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", - "@babel/plugin-proposal-optional-chaining": "^7.11.0", - "@babel/plugin-proposal-private-methods": "^7.10.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.10.4", - "@babel/plugin-transform-arrow-functions": "^7.10.4", - "@babel/plugin-transform-async-to-generator": "^7.10.4", - "@babel/plugin-transform-block-scoped-functions": "^7.10.4", - "@babel/plugin-transform-block-scoping": "^7.10.4", - "@babel/plugin-transform-classes": "^7.10.4", - "@babel/plugin-transform-computed-properties": "^7.10.4", - "@babel/plugin-transform-destructuring": "^7.10.4", - "@babel/plugin-transform-dotall-regex": "^7.10.4", - "@babel/plugin-transform-duplicate-keys": "^7.10.4", - "@babel/plugin-transform-exponentiation-operator": "^7.10.4", - "@babel/plugin-transform-for-of": "^7.10.4", - "@babel/plugin-transform-function-name": "^7.10.4", - "@babel/plugin-transform-literals": "^7.10.4", - "@babel/plugin-transform-member-expression-literals": "^7.10.4", - "@babel/plugin-transform-modules-amd": "^7.10.4", - "@babel/plugin-transform-modules-commonjs": "^7.10.4", - "@babel/plugin-transform-modules-systemjs": "^7.10.4", - "@babel/plugin-transform-modules-umd": "^7.10.4", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", - "@babel/plugin-transform-new-target": "^7.10.4", - "@babel/plugin-transform-object-super": "^7.10.4", - "@babel/plugin-transform-parameters": "^7.10.4", - "@babel/plugin-transform-property-literals": "^7.10.4", - "@babel/plugin-transform-regenerator": "^7.10.4", - "@babel/plugin-transform-reserved-words": "^7.10.4", - "@babel/plugin-transform-shorthand-properties": "^7.10.4", - "@babel/plugin-transform-spread": "^7.11.0", - "@babel/plugin-transform-sticky-regex": "^7.10.4", - "@babel/plugin-transform-template-literals": "^7.10.4", - "@babel/plugin-transform-typeof-symbol": "^7.10.4", - "@babel/plugin-transform-unicode-escapes": "^7.10.4", - "@babel/plugin-transform-unicode-regex": "^7.10.4", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.11.0", - "browserslist": "^4.12.0", - "core-js-compat": "^3.6.2", - "invariant": "^2.2.2", - "levenary": "^1.1.1", - "semver": "^5.5.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", - "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "@babel/preset-flow": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.10.4.tgz", - "integrity": "sha512-XI6l1CptQCOBv+ZKYwynyswhtOKwpZZp5n0LG1QKCo8erRhqjoQV6nvx61Eg30JHpysWQSBwA2AWRU3pBbSY5g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-transform-flow-strip-types": "^7.10.4" - } - }, - "@babel/preset-modules": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz", - "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/register": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.10.5.tgz", - "integrity": "sha512-eYHdLv43nyvmPn9bfNfrcC4+iYNwdQ8Pxk1MFJuU/U5LpSYl/PH4dFMazCYZDFVi8ueG3shvO+AQfLrxpYulQw==", - "dev": true, - "requires": { - "find-cache-dir": "^2.0.0", - "lodash": "^4.17.19", - "make-dir": "^2.1.0", - "pirates": "^4.0.0", - "source-map-support": "^0.5.16" - } - }, - "@babel/runtime": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", - "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", - "requires": { - "regenerator-runtime": "^0.13.4" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - } - } - }, - "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.5.tgz", - "integrity": "sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.5", - "@babel/types": "^7.10.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", - "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - } - }, - "@octokit/auth-token": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.2.tgz", - "integrity": "sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ==", - "dev": true, - "requires": { - "@octokit/types": "^5.0.0" - } - }, - "@octokit/endpoint": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.5.tgz", - "integrity": "sha512-70K5u6zd45ItOny6aHQAsea8HHQjlQq85yqOMe+Aj8dkhN2qSJ9T+Q3YjUjEYfPRBcuUWNgMn62DQnP/4LAIiQ==", - "dev": true, - "requires": { - "@octokit/types": "^5.0.0", - "is-plain-object": "^4.0.0", - "universal-user-agent": "^6.0.0" - }, - "dependencies": { - "is-plain-object": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz", - "integrity": "sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA==", - "dev": true - }, - "universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true - } - } - }, - "@octokit/plugin-paginate-rest": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", - "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", - "dev": true, - "requires": { - "@octokit/types": "^2.0.1" - }, - "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } - } - }, - "@octokit/plugin-request-log": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz", - "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==", - "dev": true - }, - "@octokit/plugin-rest-endpoint-methods": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", - "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", - "dev": true, - "requires": { - "@octokit/types": "^2.0.1", - "deprecation": "^2.3.1" - }, - "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } - } - }, - "@octokit/request": { - "version": "5.4.7", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.7.tgz", - "integrity": "sha512-FN22xUDP0i0uF38YMbOfx6TotpcENP5W8yJM1e/LieGXn6IoRxDMnBf7tx5RKSW4xuUZ/1P04NFZy5iY3Rax1A==", - "dev": true, - "requires": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.0.0", - "@octokit/types": "^5.0.0", - "deprecation": "^2.0.0", - "is-plain-object": "^4.0.0", - "node-fetch": "^2.3.0", - "once": "^1.4.0", - "universal-user-agent": "^6.0.0" - }, - "dependencies": { - "@octokit/request-error": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.2.tgz", - "integrity": "sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw==", - "dev": true, - "requires": { - "@octokit/types": "^5.0.1", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "is-plain-object": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz", - "integrity": "sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA==", - "dev": true - }, - "universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true - } - } - }, - "@octokit/request-error": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz", - "integrity": "sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==", - "dev": true, - "requires": { - "@octokit/types": "^2.0.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } - } - }, - "@octokit/rest": { - "version": "16.43.2", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", - "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", - "dev": true, - "requires": { - "@octokit/auth-token": "^2.4.0", - "@octokit/plugin-paginate-rest": "^1.1.1", - "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "2.4.0", - "@octokit/request": "^5.2.0", - "@octokit/request-error": "^1.0.2", - "atob-lite": "^2.0.0", - "before-after-hook": "^2.0.0", - "btoa-lite": "^1.0.0", - "deprecation": "^2.0.0", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", - "lodash.uniq": "^4.5.0", - "octokit-pagination-methods": "^1.1.0", - "once": "^1.4.0", - "universal-user-agent": "^4.0.0" - } - }, - "@octokit/types": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.2.0.tgz", - "integrity": "sha512-XjOk9y4m8xTLIKPe1NFxNWBdzA2/z3PFFA/bwf4EoH6oS8hM0Y46mEa4Cb+KCyj/tFDznJFahzQ0Aj3o1FYq4A==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - }, - "@rollup/plugin-babel": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.1.0.tgz", - "integrity": "sha512-zXBEYmfiLAMvB+ZBa6m/q9hsQYAq1sUFdjuP1F6C2pf6uQcpHwAWQveZgzS63zXdKPUYHD3Dr7BhjCqcr0bbLw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.7.4", - "@rollup/pluginutils": "^3.0.8" - } - }, - "@rollup/plugin-commonjs": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz", - "integrity": "sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.0.8", - "commondir": "^1.0.1", - "estree-walker": "^1.0.1", - "glob": "^7.1.2", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0" - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - } - }, - "@sindresorhus/is": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", - "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==", - "dev": true - }, - "@solana/web3.js": { - "version": "0.64.0", - "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-0.64.0.tgz", - "integrity": "sha512-DlNzAXgNdk7k4Pt6CfcaAutaiXJiog9hxswtzItf0q/0/Um8JvDI1YjnMONE3IKI/jyjmTaxhsQHWAQE42KofQ==", - "requires": { - "@babel/runtime": "^7.3.1", - "bn.js": "^5.0.0", - "bs58": "^4.0.1", - "buffer": "^5.4.3", - "buffer-layout": "^1.2.0", - "crypto-hash": "^1.2.2", - "esdoc-inject-style-plugin": "^1.0.0", - "jayson": "^3.0.1", - "mz": "^2.7.0", - "node-fetch": "^2.2.0", - "npm-run-all": "^4.1.5", - "rpc-websockets": "^5.0.8", - "superstruct": "^0.8.3", - "tweetnacl": "^1.0.0", - "ws": "^7.0.0" - } - }, - "@szmarczak/http-timer": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", - "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@types/cacheable-request": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", - "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "@types/connect": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", - "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", - "requires": { - "@types/node": "*" - } - }, - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "@types/express-serve-static-core": { - "version": "4.17.9", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz", - "integrity": "sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/fs-extra": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.1.tgz", - "integrity": "sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/http-cache-semantics": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", - "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/keyv": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", - "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/lodash": { - "version": "4.14.158", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.158.tgz", - "integrity": "sha512-InCEXJNTv/59yO4VSfuvNrZHt7eeNtWQEgnieIA+mIC+MOWM9arOWG2eQ8Vhk6NbOre6/BidiXhkZYeDY9U35w==" - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/node": { - "version": "10.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.6.tgz", - "integrity": "sha512-Fvm24+u85lGmV4hT5G++aht2C5I4Z4dYlWZIh62FAfFO/TfzXtPpoLI6I7AuBWkIFqZCnhFOoTT7RjjaIL5Fjg==" - }, - "@types/qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==" - }, - "@types/range-parser": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", - "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" - }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "acorn": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", - "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true - }, - "ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "optional": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "optional": true - }, - "array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "assert-args": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/assert-args/-/assert-args-1.2.1.tgz", - "integrity": "sha1-QEEDoUUqMv53iYgR5U5ZCoqTc70=", - "requires": { - "101": "^1.2.0", - "compound-subject": "0.0.1", - "debug": "^2.2.0", - "get-prototype-of": "0.0.0", - "is-capitalized": "^1.0.0", - "is-class": "0.0.4" - } - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "optional": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true, - "optional": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "optional": true - }, - "atob-lite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", - "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=", - "dev": true - }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "optional": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base-x": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", - "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "before-after-hook": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", - "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", - "dev": true - }, - "big-integer": { - "version": "1.6.48", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", - "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", - "dev": true - }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", - "dev": true, - "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "optional": true - }, - "bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", - "dev": true - }, - "bn.js": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", - "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==" - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "optional": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "optional": true - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "browserslist": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.13.0.tgz", - "integrity": "sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001093", - "electron-to-chromium": "^1.3.488", - "escalade": "^3.0.1", - "node-releases": "^1.1.58" - } - }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "requires": { - "base-x": "^3.0.2" - } - }, - "btoa-lite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", - "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", - "dev": true - }, - "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "buffer-indexof-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz", - "integrity": "sha1-qfuAbOgUXVQoUQznLyeLs2OmOL8=", - "dev": true - }, - "buffer-layout": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.0.tgz", - "integrity": "sha512-iiyRoho/ERzBUv6kFvfsrLNgTlVwOkqQcSQN7WrO3Y+c5SeuEhCn6+y1KwhM0V3ndptF5mI/RI44zkw0qcR5Jg==" - }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "optional": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cacheable-lookup": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", - "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", - "dev": true, - "requires": { - "@types/keyv": "^3.1.1", - "keyv": "^4.0.0" - } - }, - "cacheable-request": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", - "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001109", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001109.tgz", - "integrity": "sha512-4JIXRodHzdS3HdK8nSgIqXYLExOvG+D2/EenSvcub2Kp3QEADjo2v2oUn5g0n0D+UNwG9BtwKOyGcSq2qvQXvQ==", - "dev": true - }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", - "dev": true - }, - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", - "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "optional": true - }, - "circular-json": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", - "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==" - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "optional": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - }, - "dependencies": { - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - } - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "optional": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true, - "optional": true - }, - "compound-subject": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/compound-subject/-/compound-subject-0.0.1.tgz", - "integrity": "sha1-JxVUaYoVrmCLHfyv0wt7oeqJLEs=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "optional": true - }, - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" - }, - "core-js-compat": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", - "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", - "dev": true, - "requires": { - "browserslist": "^4.8.5", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", - "dev": true - }, - "crypto-hash": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.2.2.tgz", - "integrity": "sha512-rXXMXepuKg9gIfqE7I1jtVa6saLhzIkDQ2u3kTGUWYiUGsHcUa3LTsfrjPEdOY8kxKlryQtsOmJOU0F23yRJTg==" - }, - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true, - "optional": true - }, - "decompress-response": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", - "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", - "dev": true, - "requires": { - "mimic-response": "^2.0.0" - } - }, - "deep-eql": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", - "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", - "requires": { - "type-detect": "0.1.1" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "defer-to-connect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", - "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - }, - "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - } - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dotenv": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", - "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.514", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.514.tgz", - "integrity": "sha512-8vb8zKIeGlZigeDzNWWthmGeLzo5CC43Lc+CZshMs7UXFVMPNLtXJGa/txedpu3OJFrXXVheBwp9PqOJJlHQ8w==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - } - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escalade": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", - "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esdoc-inject-style-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-inject-style-plugin/-/esdoc-inject-style-plugin-1.0.0.tgz", - "integrity": "sha1-oTWXNou5+4nDZeBmSVyvl6Tey7E=", - "requires": { - "cheerio": "0.22.0", - "fs-extra": "1.0.0" - } - }, - "eslint": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.6.0.tgz", - "integrity": "sha512-QlAManNtqr7sozWm5TF4wIH9gmUm2hE3vNRUvyoYAa4y1l5/jxD/PQStEjBMQtCqZmSep8UxrcecI60hOpe61w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^1.3.0", - "espree": "^7.2.0", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - }, - "dependencies": { - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } - } - }, - "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - } - }, - "eslint-plugin-import": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", - "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", - "dev": true, - "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.3", - "eslint-module-utils": "^2.6.0", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" - }, - "dependencies": { - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } - } - }, - "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - }, - "espree": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz", - "integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==", - "dev": true, - "requires": { - "acorn": "^7.3.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", - "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" - }, - "exec-sh": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", - "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", - "dev": true, - "requires": { - "merge": "^1.2.0" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "optional": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "optional": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "optional": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - } - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "flow-bin": { - "version": "0.131.0", - "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.131.0.tgz", - "integrity": "sha512-fZmoIBcDrtLhy/NNMxwJysSYzMr1ksRcAOMi3AHSoYXfcuQqTvhGJx+wqjlIOqIwz8RRYm8J4V4JrSJbIKP+Xg==", - "dev": true - }, - "flow-typed": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/flow-typed/-/flow-typed-3.2.1.tgz", - "integrity": "sha512-vWQLZmndgdEHdy1TKTeI1DkLLa4078p6vhcKz/IZ6fcpaWLElTSG7rZi3BxlcSWfEQPxsymuSBNwAT7dCpXm6g==", - "dev": true, - "requires": { - "@octokit/rest": "^16.43.1", - "colors": "^1.4.0", - "flowgen": "^1.10.0", - "fs-extra": "^8.1.0", - "glob": "^7.1.6", - "got": "^10.5.7", - "md5": "^2.2.1", - "mkdirp": "^1.0.3", - "prettier": "^1.19.1", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "table": "^5.4.6", - "through": "^2.3.8", - "unzipper": "^0.10.8", - "which": "^2.0.2", - "yargs": "^15.1.0" - }, - "dependencies": { - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "flowgen": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/flowgen/-/flowgen-1.11.0.tgz", - "integrity": "sha512-WpoBjzcZadnAw5FatlUbvFWUWXkI2/LjrwTl5fl3MVDh+KdvYgFzgRXDDKH/O2uUlwjfpveiJJJx8TwL7Se84A==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/highlight": "^7.9.0", - "commander": "^5.1.0", - "lodash": "^4.17.15", - "prettier": "^2.0.5", - "shelljs": "^0.8.4", - "typescript": "^3.4", - "typescript-compiler": "^1.4.1-2" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true - } - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, - "optional": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "optional": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - }, - "dependencies": { - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "requires": { - "graceful-fs": "^4.1.6" - } - } - } - }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true, - "optional": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz", - "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", - "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", - "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true - } - } - }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-prototype-of": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/get-prototype-of/-/get-prototype-of-0.0.0.tgz", - "integrity": "sha1-mHcr0QcW0W3rSzIlFsRp78oorEQ=" - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, - "optional": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globby": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", - "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, - "got": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", - "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", - "dev": true, - "requires": { - "@sindresorhus/is": "^2.0.0", - "@szmarczak/http-timer": "^4.0.0", - "@types/cacheable-request": "^6.0.1", - "cacheable-lookup": "^2.0.0", - "cacheable-request": "^7.0.1", - "decompress-response": "^5.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^5.0.0", - "lowercase-keys": "^2.0.0", - "mimic-response": "^2.1.0", - "p-cancelable": "^2.0.0", - "p-event": "^4.0.0", - "responselike": "^2.0.0", - "to-readable-stream": "^2.0.0", - "type-fest": "^0.10.0" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", - "dev": true - } - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "optional": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "optional": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" - }, - "is-capitalized": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-capitalized/-/is-capitalized-1.0.0.tgz", - "integrity": "sha1-TIRktNkdPk7rRIid0s2PGwrEwTY=" - }, - "is-class": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/is-class/-/is-class-0.0.4.tgz", - "integrity": "sha1-4FdFFwW7NOOePjNZjJOpg3KWtzY=" - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "optional": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "optional": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "optional": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "requires": { - "has-symbols": "^1.0.1" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - } - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "optional": true - }, - "jayson": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jayson/-/jayson-3.3.3.tgz", - "integrity": "sha512-0bQ/vNvWyi+fzNoMvRK63m7BGU+PWwaJRVaGgJWZeAL5euOSqJtqzqyCrfiS3Sdw3OrvgKWF5f5N8ut87gxrng==", - "requires": { - "@types/connect": "^3.4.32", - "@types/express-serve-static-core": "^4.16.9", - "@types/lodash": "^4.14.139", - "@types/node": "^12.7.7", - "JSONStream": "^1.3.1", - "commander": "^2.12.2", - "es6-promisify": "^5.0.0", - "eyes": "^0.1.8", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.15", - "uuid": "^3.2.1" - }, - "dependencies": { - "@types/node": { - "version": "12.12.53", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.53.tgz", - "integrity": "sha512-51MYTDTyCziHb70wtGNFRwB4l+5JNvdqzFSkbDvpbftEgVUBEE+T5f7pROhWMp/fxp07oNIEQZd5bbfAH22ohQ==" - } - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" - }, - "keypather": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/keypather/-/keypather-1.10.2.tgz", - "integrity": "sha1-4ESWMtSz5RbyHMAUznxWRP3c5hQ=", - "requires": { - "101": "^1.0.0" - } - }, - "keyv": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.1.tgz", - "integrity": "sha512-xz6Jv6oNkbhrFCvCP7HQa8AaII8y8LRpoSm661NOKLr4uHuBwhX4epXrPQgF3+xdJnN4Esm5X0xwY4bOlALOtw==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levenary": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", - "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", - "dev": true, - "requires": { - "leven": "^3.1.0" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", - "dev": true - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" - }, - "lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=" - }, - "lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" - }, - "lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" - }, - "lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" - }, - "lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=" - }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", - "dev": true - }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, - "macos-release": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.4.1.tgz", - "integrity": "sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg==", - "dev": true - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "optional": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "optional": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "dev": true, - "requires": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" - } - }, - "memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" - }, - "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "optional": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "optional": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "optional": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "optional": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "optional": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "optional": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "optional": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "optional": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "mkdirp-promise": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", - "integrity": "sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=", - "requires": { - "mkdirp": "*" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "optional": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "optional": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "optional": true - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node-environment-flags": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", - "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-releases": { - "version": "1.1.60", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", - "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", - "dev": true - }, - "npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "requires": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "dependencies": { - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - } - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { - "boolbase": "~1.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "optional": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" - }, - "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "optional": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "optional": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "octokit-pagination-methods": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", - "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "os-name": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", - "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", - "dev": true, - "requires": { - "macos-release": "^2.2.0", - "windows-release": "^3.1.0" - } - }, - "p-cancelable": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", - "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==", - "dev": true - }, - "p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "dev": true, - "requires": { - "p-timeout": "^3.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "optional": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true, - "optional": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true - }, - "pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "optional": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", - "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "optional": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "optional": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "optional": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "optional": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "optional": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "optional": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "optional": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "optional": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "regenerate": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", - "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", - "dev": true, - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "optional": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "regexpu-core": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", - "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - } - }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", - "dev": true - }, - "regjsparser": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", - "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true, - "optional": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true, - "optional": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "optional": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", - "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true, - "optional": true - }, - "responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "optional": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "2.23.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.23.1.tgz", - "integrity": "sha512-Heyl885+lyN/giQwxA8AYT2GY3U+gOlTqVLrMQYno8Z1X9lAOpfXPiKiZCyPc25e9BLJM3Zlh957dpTlO4pa8A==", - "dev": true, - "requires": { - "fsevents": "~2.1.2" - }, - "dependencies": { - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - } - } - }, - "rollup-plugin-copy": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.3.0.tgz", - "integrity": "sha512-euDjCUSBXZa06nqnwCNADbkAcYDfzwowfZQkto9K/TFhiH+QG7I4PUsEMwM9tDgomGWJc//z7KLW8t+tZwxADA==", - "dev": true, - "requires": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "is-plain-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", - "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", - "dev": true - } - } - }, - "rpc-websockets": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-5.2.4.tgz", - "integrity": "sha512-6jqeJK/18hPTsmeiN+K9O4miZiAmrIncgxfPXHwuGWs9BClA2zC3fOnTThRWo4blkrjH59oKKi0KMxSK+wdtNw==", - "requires": { - "@babel/runtime": "^7.8.7", - "assert-args": "^1.2.1", - "babel-runtime": "^6.26.0", - "circular-json": "^0.5.9", - "eventemitter3": "^3.1.2", - "uuid": "^3.4.0", - "ws": "^5.2.2" - }, - "dependencies": { - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "optional": true, - "requires": { - "ret": "~0.1.10" - } - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "optional": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" - }, - "shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "optional": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "optional": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "optional": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, - "optional": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true, - "optional": true - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", - "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==" - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "optional": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "optional": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "optional": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "string.prototype.padend": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz", - "integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" - }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - } - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" - }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "superstruct": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.8.4.tgz", - "integrity": "sha512-48Ors8IVWZm/tMr8r0Si6+mJiB7mkD7jqvIzktjJ4+EnP5tBp0qOpiM1J8sCUorKx+TXWrfb3i1UcjdD1YK/wA==", - "requires": { - "kind-of": "^6.0.2", - "tiny-invariant": "^1.0.6" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - } - } - }, - "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "thenify": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", - "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "through": { - "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "tiny-invariant": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", - "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-readable-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", - "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==", - "dev": true - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "optional": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "optional": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", - "dev": true - }, - "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", - "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "typescript": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", - "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", - "dev": true - }, - "typescript-compiler": { - "version": "1.4.1-2", - "resolved": "https://registry.npmjs.org/typescript-compiler/-/typescript-compiler-1.4.1-2.tgz", - "integrity": "sha1-uk99si2RU0oZKdkACdzhYety/T8=", - "dev": true - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "optional": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "universal-user-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz", - "integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==", - "dev": true, - "requires": { - "os-name": "^3.1.0" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "optional": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "optional": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "optional": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "optional": true - } - } - }, - "unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "requires": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "optional": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true, - "optional": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", - "dev": true - }, - "v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "watch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", - "integrity": "sha1-NApxe952Vyb6CqB9ch4BR6VR3ww=", - "dev": true, - "requires": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "windows-release": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.1.tgz", - "integrity": "sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A==", - "dev": true, - "requires": { - "execa": "^1.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "ws": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", - "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "optional": true - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } -} diff --git a/program/js/package.json b/program/js/package.json deleted file mode 100644 index 4016239..0000000 --- a/program/js/package.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "name": "@solana/spl-token", - "version": "0.0.5", - "description": "SPL Token Javascript API", - "license": "MIT", - "author": "Solana Maintainers ", - "homepage": "https://solana.com/", - "repository": { - "type": "git", - "url": "https://github.com/solana-labs/solana-program-library" - }, - "bugs": { - "url": "https://github.com/solana-labs/solana-program-library/issues" - }, - "publishConfig": { - "access": "public" - }, - "main": "lib/index.cjs.js", - "module": "lib/index.esm.js", - "types": "lib/index.d.ts", - "files": [ - "/lib", - "/module.flow.js" - ], - "testnetDefaultChannel": "v1.3.1", - "scripts": { - "build": "rollup -c", - "start": "babel-node cli/main.js", - "lint": "npm run pretty && eslint .", - "lint:fix": "npm run lint -- --fix", - "flow": "flow", - "flow:watch": "watch 'flow' . --wait=1 --ignoreDirectoryPattern=/doc/", - "lint:watch": "watch 'npm run lint:fix' . --wait=1", - "build:program": "rm client/util/store/config.json; ../../do.sh build token", - "cluster:localnet": "rm -f .env", - "cluster:devnet": "cp cluster-devnet.env .env", - "cluster:testnet": "cp cluster-testnet.env .env", - "cluster:mainnet-beta": "cp cluster-mainnet-beta.env .env", - "localnet:update": "solana-localnet update", - "localnet:up": "rm client/util/store/config.json; set -x; solana-localnet down; set -e; solana-localnet up", - "localnet:down": "solana-localnet down", - "localnet:logs": "solana-localnet logs -f", - "pretty": "prettier --write '{,cli*/**/}*.js'" - }, - "dependencies": { - "@babel/runtime": "^7.10.5", - "@solana/web3.js": "^0.64.0", - "bn.js": "^5.0.0", - "buffer-layout": "^1.2.0", - "dotenv": "8.2.0", - "mkdirp-promise": "^5.0.1" - }, - "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/node": "^7.10.5", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-transform-runtime": "^7.10.5", - "@babel/preset-env": "^7.10.4", - "@babel/preset-flow": "^7.10.4", - "@rollup/plugin-babel": "^5.1.0", - "@rollup/plugin-commonjs": "^14.0.0", - "babel-eslint": "^10.1.0", - "eslint": "^7.4.0", - "eslint-plugin-import": "^2.22.0", - "flow-bin": "0.131.0", - "flow-typed": "^3.2.0", - "mz": "^2.7.0", - "prettier": "^2.0.5", - "rollup": "^2.23.0", - "rollup-plugin-copy": "^3.3.0", - "semver": "^7.0.0", - "watch": "^1.0.2" - }, - "engines": { - "node": ">= 10" - } -} diff --git a/program/js/rollup.config.js b/program/js/rollup.config.js deleted file mode 100644 index 211e4b7..0000000 --- a/program/js/rollup.config.js +++ /dev/null @@ -1,74 +0,0 @@ -import babel from '@rollup/plugin-babel'; -import commonjs from '@rollup/plugin-commonjs'; -import copy from 'rollup-plugin-copy'; - -function generateConfig(configType) { - const config = { - input: 'client/token.js', - plugins: [ - babel({ - configFile: './babel.rollup.config.json', - exclude: 'node_modules/**', - babelHelpers: 'runtime', - }), - commonjs(), - copy({ - targets: [{src: 'module.d.ts', dest: 'lib', rename: 'index.d.ts'}], - }), - ], - }; - - switch (configType) { - case 'browser': - // TODO: Add support - break; - case 'node': - config.output = [ - { - file: 'lib/index.cjs.js', - format: 'cjs', - sourcemap: true, - }, - { - file: 'lib/index.esm.js', - format: 'es', - sourcemap: true, - }, - ]; - - // Quash 'Unresolved dependencies' complaints for modules listed in the - // package.json "dependencies" section. Unfortunately this list is manually - // maintained. - config.external = [ - 'assert', - '@babel/runtime/core-js/get-iterator', - '@babel/runtime/core-js/json/stringify', - '@babel/runtime/core-js/object/assign', - '@babel/runtime/core-js/object/get-prototype-of', - '@babel/runtime/core-js/object/keys', - '@babel/runtime/core-js/promise', - '@babel/runtime/helpers/asyncToGenerator', - '@babel/runtime/helpers/classCallCheck', - '@babel/runtime/helpers/createClass', - '@babel/runtime/helpers/defineProperty', - '@babel/runtime/helpers/get', - '@babel/runtime/helpers/getPrototypeOf', - '@babel/runtime/helpers/inherits', - '@babel/runtime/helpers/possibleConstructorReturn', - '@babel/runtime/helpers/slicedToArray', - '@babel/runtime/helpers/toConsumableArray', - '@babel/runtime/helpers/typeof', - '@babel/runtime/regenerator', - 'bn.js', - 'buffer-layout', - '@solana/web3.js', - ]; - break; - default: - throw new Error(`Unknown configType: ${configType}`); - } - - return config; -} - -export default [generateConfig('node')]; diff --git a/program/js/url.js b/program/js/url.js deleted file mode 100644 index 3138a7c..0000000 --- a/program/js/url.js +++ /dev/null @@ -1,31 +0,0 @@ -// To connect to a public cluster, set `export LIVE=1` in your -// environment. By default, `LIVE=1` will connect to the devnet cluster. - -import {clusterApiUrl, Cluster} from '@solana/web3.js'; -import dotenv from 'dotenv'; - -function chooseCluster(): Cluster | undefined { - dotenv.config(); - if (!process.env.LIVE) return; - switch (process.env.CLUSTER) { - case 'devnet': - case 'testnet': - case 'mainnet-beta': { - return process.env.CLUSTER; - } - } - throw 'Unknown cluster "' + process.env.CLUSTER + '", check the .env file'; -} - -export const cluster = chooseCluster(); - -export const url = - process.env.RPC_URL || - (process.env.LIVE ? clusterApiUrl(cluster, false) : 'http://localhost:8899'); - -export const urlTls = - process.env.RPC_URL || - (process.env.LIVE ? clusterApiUrl(cluster, true) : 'http://localhost:8899'); - -export let walletUrl = - process.env.WALLET_URL || 'https://solana-example-webwallet.herokuapp.com/'; From 8fee2f52757cbd12c5831b9b41462df2891d3155 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Sat, 8 Aug 2020 12:41:34 -0700 Subject: [PATCH 011/335] Update token.h --- program/inc/token.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/program/inc/token.h b/program/inc/token.h index 2efb6c3..e93170e 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -11,6 +11,11 @@ #define TOKEN_MINOR_VERSION 0 #define TOKEN_PATCH_VERSION 6 +/** + * There are 10^9 lamports in one SOL + */ +#define Token_DECIMALS 9 + /** * Maximum number of multisignature signers (max N) */ From e211ce535e9f52a0059156ca1378a87cd654cd44 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Sat, 8 Aug 2020 15:27:08 -0700 Subject: [PATCH 012/335] Move program READMEs back --- program/README.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 program/README.md diff --git a/program/README.md b/program/README.md deleted file mode 100644 index 53b4e01..0000000 --- a/program/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Token program - -A Fungible Token program on the Solana blockchain. - -This program provides an interface and implementation that third parties can -utilize to create and use their tokens. - -Full documentation is available at https://spl.solana.com - -Javascript binding are available in the `./js` directory. From 7b5ebb2e78634d54b8dfac61fe5ae3cb26e4e23c Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Tue, 11 Aug 2020 16:41:56 -0600 Subject: [PATCH 013/335] Truncate SPL Token instruction data field (#260) --- program/src/instruction.rs | 151 ++++++++++++++++++++++++++++++++----- 1 file changed, 133 insertions(+), 18 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index e3e78e7..d1a950d 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -256,51 +256,85 @@ impl TokenInstruction { /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. pub fn pack(self: &Self) -> Result, ProgramError> { let mut output = vec![0u8; size_of::()]; + let mut output_len = 0; match self { Self::InitializeMint { amount, decimals } => { - output[0] = 0; + output[output_len] = 0; + output_len += size_of::(); + #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; *value = *amount; - let value = - unsafe { &mut *(&mut output[size_of::() + size_of::()] as *mut u8) }; + output_len += size_of::(); + + let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; *value = *decimals; + output_len += size_of::(); + } + Self::InitializeAccount => { + output[output_len] = 1; + output_len += size_of::(); } - Self::InitializeAccount => output[0] = 1, Self::InitializeMultisig { m } => { - output[0] = 2; + output[output_len] = 2; + output_len += size_of::(); + #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u8) }; + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u8) }; *value = *m; + output_len += size_of::(); } Self::Transfer { amount } => { - output[0] = 3; + output[output_len] = 3; + output_len += size_of::(); + #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; *value = *amount; + output_len += size_of::(); } Self::Approve { amount } => { - output[0] = 4; + output[output_len] = 4; + output_len += size_of::(); + #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; *value = *amount; + output_len += size_of::(); + } + Self::Revoke => { + output[output_len] = 5; + output_len += size_of::(); + } + Self::SetOwner => { + output[output_len] = 6; + output_len += size_of::(); } - Self::Revoke => output[0] = 5, - Self::SetOwner => output[0] = 6, Self::MintTo { amount } => { - output[0] = 7; + output[output_len] = 7; + output_len += size_of::(); + #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; *value = *amount; + output_len += size_of::(); } Self::Burn { amount } => { - output[0] = 8; + output[output_len] = 8; + output_len += size_of::(); + #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[size_of::()] as *mut u8 as *mut u64) }; + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; *value = *amount; + output_len += size_of::(); + } + Self::CloseAccount => { + output[output_len] = 9; + output_len += size_of::(); } - Self::CloseAccount => output[0] = 9, } + + output.truncate(output_len); Ok(output) } } @@ -591,3 +625,84 @@ pub fn close_account( pub fn is_valid_signer_index(index: usize) -> bool { !(index < MIN_SIGNERS || index > MAX_SIGNERS) } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_instruction_packing() { + let check = TokenInstruction::InitializeMint { + amount: 1, + decimals: 2, + }; + let packed = check.pack().unwrap(); + let expect = Vec::from([0u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeAccount; + let packed = check.pack().unwrap(); + let expect = Vec::from([1u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeMultisig { m: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([2u8, 1]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Transfer { amount: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Approve { amount: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Revoke; + let packed = check.pack().unwrap(); + let expect = Vec::from([5u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::SetOwner; + let packed = check.pack().unwrap(); + let expect = Vec::from([6u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::MintTo { amount: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Burn { amount: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::CloseAccount; + let packed = check.pack().unwrap(); + let expect = Vec::from([9u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + } +} From 7b000f25c58720f3c54f72c839b8a4a109a65e74 Mon Sep 17 00:00:00 2001 From: Jack May Date: Tue, 11 Aug 2020 16:09:36 -0700 Subject: [PATCH 014/335] cbindgen does not produce deterministic header files (#261) --- program/inc/token.h | 2 +- program/src/instruction.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index e93170e..7019ff4 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -43,7 +43,7 @@ typedef enum Token_TokenInstruction_Tag { * 1. * * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. * * If supply is zero: `[]` The owner/multisignature of the mint. - * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if + * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if * present then further minting is supported. * */ diff --git a/program/src/instruction.rs b/program/src/instruction.rs index d1a950d..efb6b4d 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -29,7 +29,7 @@ pub enum TokenInstruction { /// 1. /// * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. /// * If supply is zero: `[]` The owner/multisignature of the mint. - /// 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if + /// 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if /// present then further minting is supported. /// InitializeMint { From 9708ce508490d683f0a8b6b8196a70046384e4bc Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 12 Aug 2020 21:15:41 -0700 Subject: [PATCH 015/335] clippy --- program/src/instruction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index efb6b4d..d29f459 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -254,7 +254,7 @@ impl TokenInstruction { } /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. - pub fn pack(self: &Self) -> Result, ProgramError> { + pub fn pack(&self) -> Result, ProgramError> { let mut output = vec![0u8; size_of::()]; let mut output_len = 0; match self { From c54e420a946c4b92e5f4c3b13133e701e0f6faa2 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 12 Aug 2020 21:45:43 -0700 Subject: [PATCH 016/335] Bump version to v1.0.7 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index f370b73..68bd7c7 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "1.0.6" +version = "1.0.7" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From b34206d43e812ae9bbca93517da5d5acf15e0f25 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 13 Aug 2020 22:08:32 -0700 Subject: [PATCH 017/335] clippy --- program/src/native_mint.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs index 6e80b28..41307b3 100644 --- a/program/src/native_mint.rs +++ b/program/src/native_mint.rs @@ -13,9 +13,8 @@ mod tests { #[test] fn test_decimals() { - assert_eq!( - lamports_to_sol(42), - crate::amount_to_ui_amount(42, DECIMALS) + assert!( + lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS).abs() < f64::EPSILON ); assert_eq!( sol_to_lamports(42.), From ac8fdfad0509bc8084f96ffb2cab1a1a48c46bf8 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 13 Aug 2020 22:34:27 -0700 Subject: [PATCH 018/335] Bump token version --- program/inc/token.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/inc/token.h b/program/inc/token.h index 7019ff4..8676b6e 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -9,7 +9,7 @@ #define TOKEN_MAJOR_VERSION 1 #define TOKEN_MINOR_VERSION 0 -#define TOKEN_PATCH_VERSION 6 +#define TOKEN_PATCH_VERSION 7 /** * There are 10^9 lamports in one SOL From 7f91a0d7c7dd055dd3ec3ce26f6bcc80886ed214 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 14 Aug 2020 08:42:04 -0700 Subject: [PATCH 019/335] Remove extra whitespace --- program/inc/token.h | 2 +- program/src/instruction.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index 8676b6e..7b7be0e 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -43,7 +43,7 @@ typedef enum Token_TokenInstruction_Tag { * 1. * * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. * * If supply is zero: `[]` The owner/multisignature of the mint. - * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if + * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if * present then further minting is supported. * */ diff --git a/program/src/instruction.rs b/program/src/instruction.rs index d29f459..fc8d493 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -29,7 +29,7 @@ pub enum TokenInstruction { /// 1. /// * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. /// * If supply is zero: `[]` The owner/multisignature of the mint. - /// 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if + /// 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if /// present then further minting is supported. /// InitializeMint { From 7b8c165db66ed36f8287d8aa8e0264a450262ec7 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 14 Aug 2020 09:22:03 -0700 Subject: [PATCH 020/335] Exclude DECIMALS --- program/build.rs | 1 + program/inc/token.h | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/program/build.rs b/program/build.rs index 161616c..c85fabd 100644 --- a/program/build.rs +++ b/program/build.rs @@ -47,6 +47,7 @@ fn main() { "Account".to_string(), "Multisig".to_string(), ], + exclude: vec!["DECIMALS".to_string()], ..cbindgen::ExportConfig::default() }, parse: cbindgen::ParseConfig { diff --git a/program/inc/token.h b/program/inc/token.h index 7b7be0e..5bf5c5b 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -11,11 +11,6 @@ #define TOKEN_MINOR_VERSION 0 #define TOKEN_PATCH_VERSION 7 -/** - * There are 10^9 lamports in one SOL - */ -#define Token_DECIMALS 9 - /** * Maximum number of multisignature signers (max N) */ From 79bdfa2e8fc0612102f623d3f8c368de6f0e13e4 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 14 Aug 2020 14:13:35 -0700 Subject: [PATCH 021/335] Add token program2 --- program/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 68bd7c7..cb2951b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -31,5 +31,4 @@ rand = { version = "0.7.0"} cbindgen = "=0.14.2" [lib] -name = "spl_token" crate-type = ["cdylib", "lib"] From 4a515b6d9f32c669404824f03f986329afc27a23 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 14 Aug 2020 14:49:01 -0700 Subject: [PATCH 022/335] Back out 'Add support for self transfers (#210)' --- program/src/processor.rs | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index c50d474..759edb6 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -133,10 +133,6 @@ impl Processor { let dest_account_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; - if source_account_info.key == dest_account_info.key { - return Ok(()); - } - let mut source_data = source_account_info.data.borrow_mut(); let mut source_account: &mut Account = state::unpack(&mut source_data)?; let mut dest_data = dest_account_info.data.borrow_mut(); @@ -853,41 +849,6 @@ mod tests { ) .unwrap(); - // transfer to self - { - let instruction = transfer( - &program_id, - &account_key, - &account_key, - &owner_key, - &[], - 500, - ) - .unwrap(); - let account_account_info = AccountInfo::from(( - &instruction.accounts[0].pubkey, - instruction.accounts[0].is_signer, - &mut account_account, - )); - let owner_account_info = AccountInfo::from(( - &instruction.accounts[2].pubkey, - instruction.accounts[2].is_signer, - &mut owner_account, - )); - Processor::process( - &instruction.program_id, - &[ - account_account_info.clone(), - account_account_info, - owner_account_info, - ], - &instruction.data, - ) - .unwrap() - } - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, 1000); - // insufficient funds assert_eq!( Err(TokenError::InsufficientFunds.into()), From 8adbbd845526dd47c0f8107eec0589473fce6eda Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 14 Aug 2020 18:08:46 -0700 Subject: [PATCH 023/335] Bump version to 1.0.8 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index cb2951b..a6e3a65 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "1.0.7" +version = "1.0.8" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 3f8a2e93e9c19b4de04d1e3af8a866d68cc70651 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 20 Aug 2020 13:41:11 -0700 Subject: [PATCH 024/335] Update version --- program/inc/token.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/inc/token.h b/program/inc/token.h index 5bf5c5b..d9ef5d2 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -9,7 +9,7 @@ #define TOKEN_MAJOR_VERSION 1 #define TOKEN_MINOR_VERSION 0 -#define TOKEN_PATCH_VERSION 7 +#define TOKEN_PATCH_VERSION 8 /** * Maximum number of multisignature signers (max N) From a750e4b3cbea151e5648d67c5b4d7d7669e0d50b Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 20 Aug 2020 17:47:49 -0700 Subject: [PATCH 025/335] Remove duplicate --- program/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/program/build.rs b/program/build.rs index c85fabd..4862075 100644 --- a/program/build.rs +++ b/program/build.rs @@ -41,7 +41,6 @@ fn main() { export: cbindgen::ExportConfig { prefix: Some("Token_".to_string()), include: vec![ - "TokenInstruction".to_string(), "TokenInstruction".to_string(), "Mint".to_string(), "Account".to_string(), From 4badc18ec2e44c29a222bb7615b45109e1c663d0 Mon Sep 17 00:00:00 2001 From: Jack May Date: Tue, 25 Aug 2020 08:48:26 -0700 Subject: [PATCH 026/335] Fix overflow when amounts are u64::MAX (#310) --- program/src/error.rs | 3 + program/src/processor.rs | 160 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 161 insertions(+), 2 deletions(-) diff --git a/program/src/error.rs b/program/src/error.rs index 32f9822..46bf59c 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -43,6 +43,9 @@ pub enum TokenError { /// Invalid instruction #[error("Invalid instruction")] InvalidInstruction, + /// Operation overflowed + #[error("Operation overflowed")] + Overflow, } impl From for ProgramError { fn from(e: TokenError) -> Self { diff --git a/program/src/processor.rs b/program/src/processor.rs index 759edb6..238c0d1 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -170,7 +170,10 @@ impl Processor { }; source_account.amount -= amount; - dest_account.amount += amount; + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; if source_account.is_native { **source_account_info.lamports.borrow_mut() -= amount; @@ -304,7 +307,10 @@ impl Processor { } } - dest_account.amount += amount; + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; Ok(()) } @@ -497,6 +503,7 @@ impl PrintProgramError for TokenError { info!("Error: Instruction does not support non-native tokens") } TokenError::InvalidInstruction => info!("Error: Invalid instruction"), + TokenError::Overflow => info!("Error: Operation overflowed"), } } } @@ -2190,4 +2197,153 @@ mod tests { assert_eq!(account.amount, 0); assert_eq!(account3_account.lamports, 4); } + + #[test] + fn test_overflow() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_owner_key = pubkey_rand(); + let mut mint_owner_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create victim account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner2_account, + ], + ) + .unwrap(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, None, Some(&mint_owner_key), 0, 2).unwrap(), + vec![&mut mint_account, &mut mint_owner_account], + ) + .unwrap(); + + // mint the max to attacker + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &mint_owner_key, + &[], + 42, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // mint the max to victum + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // mint one more + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + ); + + // mint back to large amount + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + account.amount = 0; + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // transfer to burn victim + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner2_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner2_account, + ], + ) + ); + } } From 2d80af6af09ea9cdc7a60befd5c948d867f1bfc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2020 00:47:01 +0000 Subject: [PATCH 027/335] Bump solana-sdk from 1.3.2 to 1.3.4 Bumps [solana-sdk](https://github.com/solana-labs/solana) from 1.3.2 to 1.3.4. - [Release notes](https://github.com/solana-labs/solana/releases) - [Changelog](https://github.com/solana-labs/solana/blob/master/RELEASE.md) - [Commits](https://github.com/solana-labs/solana/compare/v1.3.2...v1.3.4) Signed-off-by: dependabot[bot] --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index a6e3a65..cc045fc 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,7 +21,7 @@ default = ["solana-sdk/default"] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.2.17", default-features = false, optional = true } +solana-sdk = { version = "1.3.4", default-features = false, optional = true } thiserror = "1.0" [dev-dependencies] From 5d78fccf5780f5b11e1fa939b1f49041421b95e3 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 26 Aug 2020 22:08:27 -0700 Subject: [PATCH 028/335] Remove token 1.0 --- program/Cargo.toml | 34 - program/Xargo.toml | 2 - program/build.rs | 65 - program/inc/token.h | 359 ------ program/program-id.md | 1 - program/src/entrypoint.rs | 24 - program/src/error.rs | 59 - program/src/instruction.rs | 708 ----------- program/src/lib.rs | 28 - program/src/native_mint.rs | 24 - program/src/option.rs | 965 --------------- program/src/processor.rs | 2349 ------------------------------------ program/src/state.rs | 92 -- 13 files changed, 4710 deletions(-) delete mode 100644 program/Cargo.toml delete mode 100644 program/Xargo.toml delete mode 100644 program/build.rs delete mode 100644 program/inc/token.h delete mode 100644 program/program-id.md delete mode 100644 program/src/entrypoint.rs delete mode 100644 program/src/error.rs delete mode 100644 program/src/instruction.rs delete mode 100644 program/src/lib.rs delete mode 100644 program/src/native_mint.rs delete mode 100644 program/src/option.rs delete mode 100644 program/src/processor.rs delete mode 100644 program/src/state.rs diff --git a/program/Cargo.toml b/program/Cargo.toml deleted file mode 100644 index cc045fc..0000000 --- a/program/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ - -# Note: This crate must be built using do.sh - -[package] -name = "spl-token" -version = "1.0.8" -description = "Solana Program Library Token" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" -license = "Apache-2.0" -edition = "2018" -exclude = ["js/**"] - -[features] -no-entrypoint = [] -skip-no-mangle = ["solana-sdk/skip-no-mangle"] -program = ["solana-sdk/program"] -default = ["solana-sdk/default"] - -[dependencies] -num-derive = "0.3" -num-traits = "0.2" -remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.4", default-features = false, optional = true } -thiserror = "1.0" - -[dev-dependencies] -rand = { version = "0.7.0"} - -[build-dependencies] -cbindgen = "=0.14.2" - -[lib] -crate-type = ["cdylib", "lib"] diff --git a/program/Xargo.toml b/program/Xargo.toml deleted file mode 100644 index 1744f09..0000000 --- a/program/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/program/build.rs b/program/build.rs deleted file mode 100644 index 4862075..0000000 --- a/program/build.rs +++ /dev/null @@ -1,65 +0,0 @@ -extern crate cbindgen; - -use std::env; - -fn main() { - println!("cargo:rerun-if-env-changed=SPL_CBINDGEN"); - println!("cargo:rerun-if-changed=inc/token.h"); - if std::path::Path::new("inc/token.h").exists() && env::var("SPL_CBINDGEN").is_err() { - return; - } - - println!("cargo:warning=Generating inc/token.h"); - let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let config = cbindgen::Config { - header: Some("/* Autogenerated SPL Token program C Bindings */".to_string()), - after_includes: Some(format!( - "{}{}{}", - format!( - "\n#define TOKEN_MAJOR_VERSION {}", - env!("CARGO_PKG_VERSION_MAJOR") - ), - format!( - "\n#define TOKEN_MINOR_VERSION {}", - env!("CARGO_PKG_VERSION_MINOR") - ), - format!( - "\n#define TOKEN_PATCH_VERSION {}", - env!("CARGO_PKG_VERSION_PATCH") - ) - )), - language: cbindgen::Language::C, - line_length: 80, - style: cbindgen::Style::Both, - tab_width: 4, - cpp_compat: true, - pragma_once: true, - enumeration: cbindgen::EnumConfig { - prefix_with_name: true, - ..cbindgen::EnumConfig::default() - }, - export: cbindgen::ExportConfig { - prefix: Some("Token_".to_string()), - include: vec![ - "TokenInstruction".to_string(), - "Mint".to_string(), - "Account".to_string(), - "Multisig".to_string(), - ], - exclude: vec!["DECIMALS".to_string()], - ..cbindgen::ExportConfig::default() - }, - parse: cbindgen::ParseConfig { - parse_deps: true, - include: Some(vec!["solana-sdk".to_string()]), - ..cbindgen::ParseConfig::default() - }, - ..cbindgen::Config::default() - }; - cbindgen::Builder::new() - .with_crate(crate_dir) - .with_config(config) - .generate() - .unwrap() - .write_to_file("inc/token.h"); -} diff --git a/program/inc/token.h b/program/inc/token.h deleted file mode 100644 index d9ef5d2..0000000 --- a/program/inc/token.h +++ /dev/null @@ -1,359 +0,0 @@ -/* Autogenerated SPL Token program C Bindings */ - -#pragma once - -#include -#include -#include -#include - -#define TOKEN_MAJOR_VERSION 1 -#define TOKEN_MINOR_VERSION 0 -#define TOKEN_PATCH_VERSION 8 - -/** - * Maximum number of multisignature signers (max N) - */ -#define Token_MAX_SIGNERS 11 - -/** - * Minimum number of multisignature signers (min N) - */ -#define Token_MIN_SIGNERS 1 - -/** - * Instructions supported by the token program. - */ -typedef enum Token_TokenInstruction_Tag { - /** - * Initializes a new mint and optionally deposits all the newly minted tokens in an account. - * - * The `InitializeMint` instruction requires no signers and MUST be included within - * the same Transaction as the system program's `CreateInstruction` that creates the account - * being initialized. Otherwise another party can acquire ownership of the uninitialized account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The mint to initialize. - * 1. - * * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. - * * If supply is zero: `[]` The owner/multisignature of the mint. - * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if - * present then further minting is supported. - * - */ - Token_TokenInstruction_InitializeMint, - /** - * Initializes a new account to hold tokens. If this account is associated with the native mint - * then the token balance of the initialized account will be equal to the amount of SOL in the account. - * - * The `InitializeAccount` instruction requires no signers and MUST be included within - * the same Transaction as the system program's `CreateInstruction` that creates the account - * being initialized. Otherwise another party can acquire ownership of the uninitialized account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The account to initialize. - * 1. `[]` The mint this account will be associated with. - * 2. `[]` The new account's owner/multisignature. - */ - Token_TokenInstruction_InitializeAccount, - /** - * Initializes a multisignature account with N provided signers. - * - * Multisignature accounts can used in place of any single owner/delegate accounts in any - * token instruction that require an owner/delegate to be present. The variant field represents the - * number of signers (M) required to validate this multisignature account. - * - * The `InitializeMultisig` instruction requires no signers and MUST be included within - * the same Transaction as the system program's `CreateInstruction` that creates the account - * being initialized. Otherwise another party can acquire ownership of the uninitialized account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The multisignature account to initialize. - * 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. - */ - Token_TokenInstruction_InitializeMultisig, - /** - * Transfers tokens from one account to another either directly or via a delegate. If this - * account is associated with the native mint then equal amounts of SOL and Tokens will be - * transferred to the destination account. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The source account. - * 1. `[writable]` The destination account. - * 2. '[signer]' The source account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The source account. - * 1. `[writable]` The destination account. - * 2. '[]' The source account's multisignature owner/delegate. - * 3. ..3+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_Transfer, - /** - * Approves a delegate. A delegate is given the authority over - * tokens on behalf of the source account's owner. - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[]` The delegate. - * 2. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The delegate. - * 2. '[]' The source account's multisignature owner. - * 3. ..3+M '[signer]' M signer accounts - */ - Token_TokenInstruction_Approve, - /** - * Revokes the delegate's authority. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. '[]' The source account's multisignature owner. - * 2. ..2+M '[signer]' M signer accounts - */ - Token_TokenInstruction_Revoke, - /** - * Sets a new owner of a mint or account. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The mint or account to change the owner of. - * 1. `[]` The new owner/delegate/multisignature. - * 2. `[signer]` The owner of the mint or account. - * - * * Multisignature owner - * 0. `[writable]` The mint or account to change the owner of. - * 1. `[]` The new owner/delegate/multisignature. - * 2. `[]` The mint's or account's multisignature owner. - * 3. ..3+M '[signer]' M signer accounts - */ - Token_TokenInstruction_SetOwner, - /** - * Mints new tokens to an account. The native mint does not support minting. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's owner. - * - * * Multisignature owner - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature owner. - * 3. ..3+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_MintTo, - /** - * Burns tokens by removing them from an account. `Burn` does not support accounts - * associated with the native mint, use `CloseAccount` instead. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[signer]` The account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[]` The account's multisignature owner/delegate. - * 2. ..2+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_Burn, - /** - * Close an account by transferring all its SOL to the destination account. - * Non-native accounts may only be closed if its token amount is zero. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to close. - * 1. '[writable]' The destination account. - * 2. `[signer]` The account's owner. - * - * * Multisignature owner - * 0. `[writable]` The account to close. - * 1. '[writable]' The destination account. - * 2. `[]` The account's multisignature owner. - * 3. ..3+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_CloseAccount, -} Token_TokenInstruction_Tag; - -typedef struct Token_TokenInstruction_Token_InitializeMint_Body { - /** - * Initial amount of tokens to mint. - */ - uint64_t amount; - /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_InitializeMint_Body; - -typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { - /** - * The number of signers (M) required to validate this multisignature account. - */ - uint8_t m; -} Token_TokenInstruction_Token_InitializeMultisig_Body; - -typedef struct Token_TokenInstruction_Token_Transfer_Body { - /** - * The amount of tokens to transfer. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Transfer_Body; - -typedef struct Token_TokenInstruction_Token_Approve_Body { - /** - * The amount of tokens the delegate is approved for. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Approve_Body; - -typedef struct Token_TokenInstruction_Token_MintTo_Body { - /** - * The amount of new tokens to mint. - */ - uint64_t amount; -} Token_TokenInstruction_Token_MintTo_Body; - -typedef struct Token_TokenInstruction_Token_Burn_Body { - /** - * The amount of tokens to burn. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Burn_Body; - -typedef struct Token_TokenInstruction { - Token_TokenInstruction_Tag tag; - union { - Token_TokenInstruction_Token_InitializeMint_Body initialize_mint; - Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; - Token_TokenInstruction_Token_Transfer_Body transfer; - Token_TokenInstruction_Token_Approve_Body approve; - Token_TokenInstruction_Token_MintTo_Body mint_to; - Token_TokenInstruction_Token_Burn_Body burn; - }; -} Token_TokenInstruction; - -typedef uint8_t Token_Pubkey[32]; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_Pubkey_Tag { - /** - * No value - */ - Token_COption_Pubkey_None_Pubkey, - /** - * Some value `T` - */ - Token_COption_Pubkey_Some_Pubkey, -} Token_COption_Pubkey_Tag; - -typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { - Token_Pubkey _0; -} Token_COption_Pubkey_Token_Some_Body_Pubkey; - -typedef struct Token_COption_Pubkey { - Token_COption_Pubkey_Tag tag; - union { - Token_COption_Pubkey_Token_Some_Body_Pubkey some; - }; -} Token_COption_Pubkey; - -/** - * Mint data. - */ -typedef struct Token_Mint { - /** - * Optional owner, used to mint new tokens. The owner may only - * be provided during mint creation. If no owner is present then the mint - * has a fixed supply and no further tokens may be minted. - */ - Token_COption_Pubkey owner; - /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; -} Token_Mint; - -/** - * Account data. - */ -typedef struct Token_Account { - /** - * The mint associated with this account - */ - Token_Pubkey mint; - /** - * The owner of this account. - */ - Token_Pubkey owner; - /** - * The amount of tokens this account holds. - */ - uint64_t amount; - /** - * If `delegate` is `Some` then `delegated_amount` represents - * the amount authorized by the delegate - */ - Token_COption_Pubkey delegate; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; - /** - * Is this a native token - */ - bool is_native; - /** - * The amount delegated - */ - uint64_t delegated_amount; -} Token_Account; - -/** - * Multisignature data. - */ -typedef struct Token_Multisig { - /** - * Number of signers required - */ - uint8_t m; - /** - * Number of valid signers - */ - uint8_t n; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; - /** - * Signer public keys - */ - Token_Pubkey signers[Token_MAX_SIGNERS]; -} Token_Multisig; diff --git a/program/program-id.md b/program/program-id.md deleted file mode 100644 index 77df2a0..0000000 --- a/program/program-id.md +++ /dev/null @@ -1 +0,0 @@ -TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs deleted file mode 100644 index b5594ca..0000000 --- a/program/src/entrypoint.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Program entrypoint - -#![cfg(feature = "program")] -#![cfg(not(feature = "no-entrypoint"))] - -use crate::{error::TokenError, processor::Processor}; -use solana_sdk::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, -}; - -entrypoint!(process_instruction); -fn process_instruction<'a>( - program_id: &Pubkey, - accounts: &'a [AccountInfo<'a>], - instruction_data: &[u8], -) -> ProgramResult { - if let Err(error) = Processor::process(program_id, accounts, instruction_data) { - // catch the error so we can print it - error.print::(); - return Err(error); - } - Ok(()) -} diff --git a/program/src/error.rs b/program/src/error.rs deleted file mode 100644 index 46bf59c..0000000 --- a/program/src/error.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Error types - -use num_derive::FromPrimitive; -use solana_sdk::{decode_error::DecodeError, program_error::ProgramError}; -use thiserror::Error; - -/// Errors that may be returned by the Token program. -#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] -pub enum TokenError { - /// Insufficient funds for the operation requested. - #[error("Insufficient funds")] - InsufficientFunds, - /// Account not associated with this Mint. - #[error("Account not associated with this Mint")] - MintMismatch, - /// Owner does not match. - #[error("Owner does not match")] - OwnerMismatch, - /// This token's supply is fixed and new tokens cannot be minted. - #[error("Fixed supply")] - FixedSupply, - /// The account cannot be initialized because it is already being used. - #[error("AlreadyInUse")] - AlreadyInUse, - /// An owner is required if initial supply is zero. - #[error("An owner is required if supply is zero")] - OwnerRequiredIfNoInitialSupply, - /// Invalid number of provided signers. - #[error("Invalid number of provided signers")] - InvalidNumberOfProvidedSigners, - /// Invalid number of required signers. - #[error("Invalid number of required signers")] - InvalidNumberOfRequiredSigners, - /// State is uninitialized. - #[error("State is unititialized")] - UninitializedState, - /// Instruction does not support native tokens - #[error("Instruction does not support native tokens")] - NativeNotSupported, - /// Instruction does not support non-native tokens - #[error("Instruction does not support non-native tokens")] - NonNativeNotSupported, - /// Invalid instruction - #[error("Invalid instruction")] - InvalidInstruction, - /// Operation overflowed - #[error("Operation overflowed")] - Overflow, -} -impl From for ProgramError { - fn from(e: TokenError) -> Self { - ProgramError::Custom(e as u32) - } -} -impl DecodeError for TokenError { - fn type_of() -> &'static str { - "TokenError" - } -} diff --git a/program/src/instruction.rs b/program/src/instruction.rs deleted file mode 100644 index fc8d493..0000000 --- a/program/src/instruction.rs +++ /dev/null @@ -1,708 +0,0 @@ -//! Instruction types - -use crate::error::TokenError; -use solana_sdk::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - pubkey::Pubkey, -}; -use std::mem::size_of; - -/// Minimum number of multisignature signers (min N) -pub const MIN_SIGNERS: usize = 1; -/// Maximum number of multisignature signers (max N) -pub const MAX_SIGNERS: usize = 11; - -/// Instructions supported by the token program. -#[repr(C)] -#[derive(Clone, Debug, PartialEq)] -pub enum TokenInstruction { - /// Initializes a new mint and optionally deposits all the newly minted tokens in an account. - /// - /// The `InitializeMint` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateInstruction` that creates the account - /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The mint to initialize. - /// 1. - /// * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. - /// * If supply is zero: `[]` The owner/multisignature of the mint. - /// 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if - /// present then further minting is supported. - /// - InitializeMint { - /// Initial amount of tokens to mint. - amount: u64, - /// Number of base 10 digits to the right of the decimal place. - decimals: u8, - }, - /// Initializes a new account to hold tokens. If this account is associated with the native mint - /// then the token balance of the initialized account will be equal to the amount of SOL in the account. - /// - /// The `InitializeAccount` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateInstruction` that creates the account - /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The account to initialize. - /// 1. `[]` The mint this account will be associated with. - /// 2. `[]` The new account's owner/multisignature. - InitializeAccount, - /// Initializes a multisignature account with N provided signers. - /// - /// Multisignature accounts can used in place of any single owner/delegate accounts in any - /// token instruction that require an owner/delegate to be present. The variant field represents the - /// number of signers (M) required to validate this multisignature account. - /// - /// The `InitializeMultisig` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateInstruction` that creates the account - /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. - /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` The multisignature account to initialize. - /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. - InitializeMultisig { - /// The number of signers (M) required to validate this multisignature account. - m: u8, - }, - /// Transfers tokens from one account to another either directly or via a delegate. If this - /// account is associated with the native mint then equal amounts of SOL and Tokens will be - /// transferred to the destination account. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[writable]` The destination account. - /// 2. '[signer]' The source account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The source account. - /// 1. `[writable]` The destination account. - /// 2. '[]' The source account's multisignature owner/delegate. - /// 3. ..3+M '[signer]' M signer accounts. - Transfer { - /// The amount of tokens to transfer. - amount: u64, - }, - /// Approves a delegate. A delegate is given the authority over - /// tokens on behalf of the source account's owner. - - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The source account. - /// 1. `[]` The delegate. - /// 2. `[signer]` The source account owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The source account. - /// 1. `[]` The delegate. - /// 2. '[]' The source account's multisignature owner. - /// 3. ..3+M '[signer]' M signer accounts - Approve { - /// The amount of tokens the delegate is approved for. - amount: u64, - }, - /// Revokes the delegate's authority. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The source account. - /// 1. `[signer]` The source account owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The source account. - /// 1. '[]' The source account's multisignature owner. - /// 2. ..2+M '[signer]' M signer accounts - Revoke, - /// Sets a new owner of a mint or account. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The mint or account to change the owner of. - /// 1. `[]` The new owner/delegate/multisignature. - /// 2. `[signer]` The owner of the mint or account. - /// - /// * Multisignature owner - /// 0. `[writable]` The mint or account to change the owner of. - /// 1. `[]` The new owner/delegate/multisignature. - /// 2. `[]` The mint's or account's multisignature owner. - /// 3. ..3+M '[signer]' M signer accounts - SetOwner, - /// Mints new tokens to an account. The native mint does not support minting. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[signer]` The mint's owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The mint. - /// 1. `[writable]` The account to mint tokens to. - /// 2. `[]` The mint's multisignature owner. - /// 3. ..3+M '[signer]' M signer accounts. - MintTo { - /// The amount of new tokens to mint. - amount: u64, - }, - /// Burns tokens by removing them from an account. `Burn` does not support accounts - /// associated with the native mint, use `CloseAccount` instead. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[signer]` The account's owner/delegate. - /// - /// * Multisignature owner/delegate - /// 0. `[writable]` The account to burn from. - /// 1. `[]` The account's multisignature owner/delegate. - /// 2. ..2+M '[signer]' M signer accounts. - Burn { - /// The amount of tokens to burn. - amount: u64, - }, - /// Close an account by transferring all its SOL to the destination account. - /// Non-native accounts may only be closed if its token amount is zero. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[writable]` The account to close. - /// 1. '[writable]' The destination account. - /// 2. `[signer]` The account's owner. - /// - /// * Multisignature owner - /// 0. `[writable]` The account to close. - /// 1. '[writable]' The destination account. - /// 2. `[]` The account's multisignature owner. - /// 3. ..3+M '[signer]' M signer accounts. - CloseAccount, -} -impl TokenInstruction { - /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). - pub fn unpack(input: &[u8]) -> Result { - if input.len() < size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - Ok(match input[0] { - 0 => { - if input.len() < size_of::() + size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - let decimals = - unsafe { *(&input[size_of::() + size_of::()] as *const u8) }; - Self::InitializeMint { amount, decimals } - } - 1 => Self::InitializeAccount, - 2 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let m = unsafe { *(&input[1] as *const u8) }; - Self::InitializeMultisig { m } - } - 3 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - Self::Transfer { amount } - } - 4 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - Self::Approve { amount } - } - 5 => Self::Revoke, - 6 => Self::SetOwner, - 7 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - Self::MintTo { amount } - } - 8 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - Self::Burn { amount } - } - 9 => Self::CloseAccount, - _ => return Err(TokenError::InvalidInstruction.into()), - }) - } - - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. - pub fn pack(&self) -> Result, ProgramError> { - let mut output = vec![0u8; size_of::()]; - let mut output_len = 0; - match self { - Self::InitializeMint { amount, decimals } => { - output[output_len] = 0; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - - let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; - *value = *decimals; - output_len += size_of::(); - } - Self::InitializeAccount => { - output[output_len] = 1; - output_len += size_of::(); - } - Self::InitializeMultisig { m } => { - output[output_len] = 2; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u8) }; - *value = *m; - output_len += size_of::(); - } - Self::Transfer { amount } => { - output[output_len] = 3; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - } - Self::Approve { amount } => { - output[output_len] = 4; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - } - Self::Revoke => { - output[output_len] = 5; - output_len += size_of::(); - } - Self::SetOwner => { - output[output_len] = 6; - output_len += size_of::(); - } - Self::MintTo { amount } => { - output[output_len] = 7; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - } - Self::Burn { amount } => { - output[output_len] = 8; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - } - Self::CloseAccount => { - output[output_len] = 9; - output_len += size_of::(); - } - } - - output.truncate(output_len); - Ok(output) - } -} - -/// Creates a 'InitializeMint' instruction. -pub fn initialize_mint( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - account_pubkey: Option<&Pubkey>, - owner_pubkey: Option<&Pubkey>, - amount: u64, - decimals: u8, -) -> Result { - let data = TokenInstruction::InitializeMint { amount, decimals }.pack()?; - - let mut accounts = vec![AccountMeta::new(*mint_pubkey, false)]; - if amount != 0 { - match account_pubkey { - Some(pubkey) => accounts.push(AccountMeta::new(*pubkey, false)), - None => { - return Err(ProgramError::NotEnoughAccountKeys); - } - } - } - match owner_pubkey { - Some(pubkey) => accounts.push(AccountMeta::new_readonly(*pubkey, false)), - None => { - if amount == 0 { - return Err(TokenError::OwnerRequiredIfNoInitialSupply.into()); - } - } - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeAccount` instruction. -pub fn initialize_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - mint_pubkey: &Pubkey, - owner_pubkey: &Pubkey, -) -> Result { - let data = TokenInstruction::InitializeAccount.pack()?; - - let accounts = vec![ - AccountMeta::new(*account_pubkey, false), - AccountMeta::new_readonly(*mint_pubkey, false), - AccountMeta::new_readonly(*owner_pubkey, false), - ]; - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `InitializeMultisig` instruction. -pub fn initialize_multisig( - token_program_id: &Pubkey, - multisig_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - m: u8, -) -> Result { - if !is_valid_signer_index(m as usize) - || !is_valid_signer_index(signer_pubkeys.len()) - || m as usize > signer_pubkeys.len() - { - return Err(ProgramError::MissingRequiredSignature); - } - let data = TokenInstruction::InitializeMultisig { m }.pack()?; - - let mut accounts = Vec::with_capacity(1 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*multisig_pubkey, false)); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Transfer` instruction. -pub fn transfer( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - destination_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - let data = TokenInstruction::Transfer { amount }.pack()?; - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new(*destination_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates an `Approve` instruction. -pub fn approve( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - delegate_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - let data = TokenInstruction::Approve { amount }.pack()?; - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Revoke` instruction. -pub fn revoke( - token_program_id: &Pubkey, - source_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - let data = TokenInstruction::Revoke.pack()?; - - let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); - accounts.push(AccountMeta::new_readonly(*source_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `SetOwner` instruction. -pub fn set_owner( - token_program_id: &Pubkey, - owned_pubkey: &Pubkey, - new_owner_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - let data = TokenInstruction::SetOwner.pack()?; - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*owned_pubkey, false)); - accounts.push(AccountMeta::new_readonly(*new_owner_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `MintTo` instruction. -pub fn mint_to( - token_program_id: &Pubkey, - mint_pubkey: &Pubkey, - account_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - let data = TokenInstruction::MintTo { amount }.pack()?; - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*mint_pubkey, false)); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `Burn` instruction. -pub fn burn( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - authority_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], - amount: u64, -) -> Result { - let data = TokenInstruction::Burn { amount }.pack()?; - - let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *authority_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Creates a `CloseAccount` instruction. -pub fn close_account( - token_program_id: &Pubkey, - account_pubkey: &Pubkey, - destination_pubkey: &Pubkey, - owner_pubkey: &Pubkey, - signer_pubkeys: &[&Pubkey], -) -> Result { - let data = TokenInstruction::CloseAccount.pack()?; - - let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); - accounts.push(AccountMeta::new(*account_pubkey, false)); - accounts.push(AccountMeta::new(*destination_pubkey, false)); - accounts.push(AccountMeta::new_readonly( - *owner_pubkey, - signer_pubkeys.is_empty(), - )); - for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); - } - - Ok(Instruction { - program_id: *token_program_id, - accounts, - data, - }) -} - -/// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS -pub fn is_valid_signer_index(index: usize) -> bool { - !(index < MIN_SIGNERS || index > MAX_SIGNERS) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_instruction_packing() { - let check = TokenInstruction::InitializeMint { - amount: 1, - decimals: 2, - }; - let packed = check.pack().unwrap(); - let expect = Vec::from([0u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeAccount; - let packed = check.pack().unwrap(); - let expect = Vec::from([1u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::InitializeMultisig { m: 1 }; - let packed = check.pack().unwrap(); - let expect = Vec::from([2u8, 1]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Transfer { amount: 1 }; - let packed = check.pack().unwrap(); - let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Approve { amount: 1 }; - let packed = check.pack().unwrap(); - let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Revoke; - let packed = check.pack().unwrap(); - let expect = Vec::from([5u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::SetOwner; - let packed = check.pack().unwrap(); - let expect = Vec::from([6u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::MintTo { amount: 1 }; - let packed = check.pack().unwrap(); - let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::Burn { amount: 1 }; - let packed = check.pack().unwrap(); - let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - - let check = TokenInstruction::CloseAccount; - let packed = check.pack().unwrap(); - let expect = Vec::from([9u8]); - assert_eq!(packed, expect); - let unpacked = TokenInstruction::unpack(&expect).unwrap(); - assert_eq!(unpacked, check); - } -} diff --git a/program/src/lib.rs b/program/src/lib.rs deleted file mode 100644 index bc39c05..0000000 --- a/program/src/lib.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![deny(missing_docs)] - -//! An ERC20-like Token program for the Solana blockchain - -pub mod entrypoint; -pub mod error; -pub mod instruction; -pub mod native_mint; -pub mod option; -pub mod processor; -pub mod state; - -// Export current solana-sdk types for downstream users who may also be building with a different -// solana-sdk version -pub use solana_sdk; - -/// Convert the UI representation of a token amount (using the decimals field defined in its mint) -/// to the raw amount -pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { - (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 -} - -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) -pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { - amount as f64 / 10_usize.pow(decimals as u32) as f64 -} - -solana_sdk::declare_id!("TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"); diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs deleted file mode 100644 index 41307b3..0000000 --- a/program/src/native_mint.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! The Mint that represents the native token - -/// There are 10^9 lamports in one SOL -pub const DECIMALS: u8 = 9; - -// The Mint for native SOL Token accounts -solana_sdk::declare_id!("So11111111111111111111111111111111111111111"); - -#[cfg(test)] -mod tests { - use super::*; - use solana_sdk::native_token::*; - - #[test] - fn test_decimals() { - assert!( - lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS).abs() < f64::EPSILON - ); - assert_eq!( - sol_to_lamports(42.), - crate::ui_amount_to_amount(42., DECIMALS) - ); - } -} diff --git a/program/src/option.rs b/program/src/option.rs deleted file mode 100644 index 914bb51..0000000 --- a/program/src/option.rs +++ /dev/null @@ -1,965 +0,0 @@ -//! A C representation of Rust's `std::option::Option` used accross the FFI -//! boundary for Solana program interfaces -//! -//! This implementation mostly matches `std::option` except iterators since the iteration -//! trait requires returning `std::option::Option` - -use std::pin::Pin; -use std::{ - convert, hint, mem, - ops::{Deref, DerefMut}, -}; - -/// A C representation of Rust's `std::option::Option` -#[repr(C)] -#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] -pub enum COption { - /// No value - None, - /// Some value `T` - Some(T), -} - -///////////////////////////////////////////////////////////////////////////// -// Type implementation -///////////////////////////////////////////////////////////////////////////// - -impl COption { - ///////////////////////////////////////////////////////////////////////// - // Querying the contained values - ///////////////////////////////////////////////////////////////////////// - - /// Returns `true` if the option is a [`COption::Some`] value. - /// - /// # Examples - /// - /// ```ignore - /// let x: COption = COption::Some(2); - /// assert_eq!(x.is_some(), true); - /// - /// let x: COption = COption::None; - /// assert_eq!(x.is_some(), false); - /// ``` - /// - /// [`COption::Some`]: #variant.COption::Some - #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] - #[inline] - pub fn is_some(&self) -> bool { - match *self { - COption::Some(_) => true, - COption::None => false, - } - } - - /// Returns `true` if the option is a [`COption::None`] value. - /// - /// # Examples - /// - /// ```ignore - /// let x: COption = COption::Some(2); - /// assert_eq!(x.is_none(), false); - /// - /// let x: COption = COption::None; - /// assert_eq!(x.is_none(), true); - /// ``` - /// - /// [`COption::None`]: #variant.COption::None - #[must_use = "if you intended to assert that this doesn't have a value, consider \ - `.and_then(|| panic!(\"`COption` had a value when expected `COption::None`\"))` instead"] - #[inline] - pub fn is_none(&self) -> bool { - !self.is_some() - } - - /// Returns `true` if the option is a [`COption::Some`] value containing the given value. - /// - /// # Examples - /// - /// ```ignore - /// #![feature(option_result_contains)] - /// - /// let x: COption = COption::Some(2); - /// assert_eq!(x.contains(&2), true); - /// - /// let x: COption = COption::Some(3); - /// assert_eq!(x.contains(&2), false); - /// - /// let x: COption = COption::None; - /// assert_eq!(x.contains(&2), false); - /// ``` - #[must_use] - #[inline] - pub fn contains(&self, x: &U) -> bool - where - U: PartialEq, - { - match self { - COption::Some(y) => x == y, - COption::None => false, - } - } - - ///////////////////////////////////////////////////////////////////////// - // Adapter for working with references - ///////////////////////////////////////////////////////////////////////// - - /// Converts from `&COption` to `COption<&T>`. - /// - /// # Examples - /// - /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, preserving the original. - /// The [`map`] method takes the `self` argument by value, consuming the original, - /// so this technique uses `as_ref` to first take an `COption` to a reference - /// to the value inside the original. - /// - /// [`map`]: enum.COption.html#method.map - /// [`String`]: ../../std/string/struct.String.html - /// [`usize`]: ../../std/primitive.usize.html - /// - /// ```ignore - /// let text: COption = COption::Some("Hello, world!".to_string()); - /// // First, cast `COption` to `COption<&String>` with `as_ref`, - /// // then consume *that* with `map`, leaving `text` on the stack. - /// let text_length: COption = text.as_ref().map(|s| s.len()); - /// println!("still can print text: {:?}", text); - /// ``` - #[inline] - pub fn as_ref(&self) -> COption<&T> { - match *self { - COption::Some(ref x) => COption::Some(x), - COption::None => COption::None, - } - } - - /// Converts from `&mut COption` to `COption<&mut T>`. - /// - /// # Examples - /// - /// ```ignore - /// let mut x = COption::Some(2); - /// match x.as_mut() { - /// COption::Some(v) => *v = 42, - /// COption::None => {}, - /// } - /// assert_eq!(x, COption::Some(42)); - /// ``` - #[inline] - pub fn as_mut(&mut self) -> COption<&mut T> { - match *self { - COption::Some(ref mut x) => COption::Some(x), - COption::None => COption::None, - } - } - - /// Converts from [`Pin`]`<&COption>` to `COption<`[`Pin`]`<&T>>`. - /// - /// [`Pin`]: ../pin/struct.Pin.html - #[inline] - #[allow(clippy::wrong_self_convention)] - pub fn as_pin_ref(self: Pin<&Self>) -> COption> { - unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } - } - - /// Converts from [`Pin`]`<&mut COption>` to `COption<`[`Pin`]`<&mut T>>`. - /// - /// [`Pin`]: ../pin/struct.Pin.html - #[inline] - #[allow(clippy::wrong_self_convention)] - pub fn as_pin_mut(self: Pin<&mut Self>) -> COption> { - unsafe { - Pin::get_unchecked_mut(self) - .as_mut() - .map(|x| Pin::new_unchecked(x)) - } - } - - ///////////////////////////////////////////////////////////////////////// - // Getting to contained values - ///////////////////////////////////////////////////////////////////////// - - /// Unwraps an option, yielding the content of a [`COption::Some`]. - /// - /// # Panics - /// - /// Panics if the value is a [`COption::None`] with a custom panic message provided by - /// `msg`. - /// - /// [`COption::Some`]: #variant.COption::Some - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("value"); - /// assert_eq!(x.expect("the world is ending"), "value"); - /// ``` - /// - /// ```ignore{.should_panic} - /// let x: COption<&str> = COption::None; - /// x.expect("the world is ending"); // panics with `the world is ending` - /// ``` - #[inline] - pub fn expect(self, msg: &str) -> T { - match self { - COption::Some(val) => val, - COption::None => expect_failed(msg), - } - } - - /// Moves the value `v` out of the `COption` if it is [`COption::Some(v)`]. - /// - /// In general, because this function may panic, its use is discouraged. - /// Instead, prefer to use pattern matching and handle the [`COption::None`] - /// case explicitly. - /// - /// # Panics - /// - /// Panics if the self value equals [`COption::None`]. - /// - /// [`COption::Some(v)`]: #variant.COption::Some - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("air"); - /// assert_eq!(x.unwrap(), "air"); - /// ``` - /// - /// ```ignore{.should_panic} - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.unwrap(), "air"); // fails - /// ``` - #[inline] - pub fn unwrap(self) -> T { - match self { - COption::Some(val) => val, - COption::None => panic!("called `COption::unwrap()` on a `COption::None` value"), - } - } - - /// Returns the contained value or a default. - /// - /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing - /// the result of a function call, it is recommended to use [`unwrap_or_else`], - /// which is lazily evaluated. - /// - /// [`unwrap_or_else`]: #method.unwrap_or_else - /// - /// # Examples - /// - /// ```ignore - /// assert_eq!(COption::Some("car").unwrap_or("bike"), "car"); - /// assert_eq!(COption::None.unwrap_or("bike"), "bike"); - /// ``` - #[inline] - pub fn unwrap_or(self, def: T) -> T { - match self { - COption::Some(x) => x, - COption::None => def, - } - } - - /// Returns the contained value or computes it from a closure. - /// - /// # Examples - /// - /// ```ignore - /// let k = 10; - /// assert_eq!(COption::Some(4).unwrap_or_else(|| 2 * k), 4); - /// assert_eq!(COption::None.unwrap_or_else(|| 2 * k), 20); - /// ``` - #[inline] - pub fn unwrap_or_else T>(self, f: F) -> T { - match self { - COption::Some(x) => x, - COption::None => f(), - } - } - - ///////////////////////////////////////////////////////////////////////// - // Transforming contained values - ///////////////////////////////////////////////////////////////////////// - - /// Maps an `COption` to `COption` by applying a function to a contained value. - /// - /// # Examples - /// - /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, consuming the original: - /// - /// [`String`]: ../../std/string/struct.String.html - /// [`usize`]: ../../std/primitive.usize.html - /// - /// ```ignore - /// let maybe_some_string = COption::Some(String::from("Hello, World!")); - /// // `COption::map` takes self *by value*, consuming `maybe_some_string` - /// let maybe_some_len = maybe_some_string.map(|s| s.len()); - /// - /// assert_eq!(maybe_some_len, COption::Some(13)); - /// ``` - #[inline] - pub fn map U>(self, f: F) -> COption { - match self { - COption::Some(x) => COption::Some(f(x)), - COption::None => COption::None, - } - } - - /// Applies a function to the contained value (if any), - /// or returns the provided default (if not). - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("foo"); - /// assert_eq!(x.map_or(42, |v| v.len()), 3); - /// - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.map_or(42, |v| v.len()), 42); - /// ``` - #[inline] - pub fn map_or U>(self, default: U, f: F) -> U { - match self { - COption::Some(t) => f(t), - COption::None => default, - } - } - - /// Applies a function to the contained value (if any), - /// or computes a default (if not). - /// - /// # Examples - /// - /// ```ignore - /// let k = 21; - /// - /// let x = COption::Some("foo"); - /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3); - /// - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42); - /// ``` - #[inline] - pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { - match self { - COption::Some(t) => f(t), - COption::None => default(), - } - } - - /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to - /// [`Ok(v)`] and [`COption::None`] to [`Err(err)`]. - /// - /// Arguments passed to `ok_or` are eagerly evaluated; if you are passing the - /// result of a function call, it is recommended to use [`ok_or_else`], which is - /// lazily evaluated. - /// - /// [`Result`]: ../../std/result/enum.Result.html - /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Err(err)`]: ../../std/result/enum.Result.html#variant.Err - /// [`COption::None`]: #variant.COption::None - /// [`COption::Some(v)`]: #variant.COption::Some - /// [`ok_or_else`]: #method.ok_or_else - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("foo"); - /// assert_eq!(x.ok_or(0), Ok("foo")); - /// - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.ok_or(0), Err(0)); - /// ``` - #[inline] - pub fn ok_or(self, err: E) -> Result { - match self { - COption::Some(v) => Ok(v), - COption::None => Err(err), - } - } - - /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to - /// [`Ok(v)`] and [`COption::None`] to [`Err(err())`]. - /// - /// [`Result`]: ../../std/result/enum.Result.html - /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Err(err())`]: ../../std/result/enum.Result.html#variant.Err - /// [`COption::None`]: #variant.COption::None - /// [`COption::Some(v)`]: #variant.COption::Some - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("foo"); - /// assert_eq!(x.ok_or_else(|| 0), Ok("foo")); - /// - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.ok_or_else(|| 0), Err(0)); - /// ``` - #[inline] - pub fn ok_or_else E>(self, err: F) -> Result { - match self { - COption::Some(v) => Ok(v), - COption::None => Err(err()), - } - } - - ///////////////////////////////////////////////////////////////////////// - // Boolean operations on the values, eager and lazy - ///////////////////////////////////////////////////////////////////////// - - /// Returns [`COption::None`] if the option is [`COption::None`], otherwise returns `optb`. - /// - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some(2); - /// let y: COption<&str> = COption::None; - /// assert_eq!(x.and(y), COption::None); - /// - /// let x: COption = COption::None; - /// let y = COption::Some("foo"); - /// assert_eq!(x.and(y), COption::None); - /// - /// let x = COption::Some(2); - /// let y = COption::Some("foo"); - /// assert_eq!(x.and(y), COption::Some("foo")); - /// - /// let x: COption = COption::None; - /// let y: COption<&str> = COption::None; - /// assert_eq!(x.and(y), COption::None); - /// ``` - #[inline] - pub fn and(self, optb: COption) -> COption { - match self { - COption::Some(_) => optb, - COption::None => COption::None, - } - } - - /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `f` with the - /// wrapped value and returns the result. - /// - /// COption::Some languages call this operation flatmap. - /// - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// fn sq(x: u32) -> COption { COption::Some(x * x) } - /// fn nope(_: u32) -> COption { COption::None } - /// - /// assert_eq!(COption::Some(2).and_then(sq).and_then(sq), COption::Some(16)); - /// assert_eq!(COption::Some(2).and_then(sq).and_then(nope), COption::None); - /// assert_eq!(COption::Some(2).and_then(nope).and_then(sq), COption::None); - /// assert_eq!(COption::None.and_then(sq).and_then(sq), COption::None); - /// ``` - #[inline] - pub fn and_then COption>(self, f: F) -> COption { - match self { - COption::Some(x) => f(x), - COption::None => COption::None, - } - } - - /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `predicate` - /// with the wrapped value and returns: - /// - /// - [`COption::Some(t)`] if `predicate` returns `true` (where `t` is the wrapped - /// value), and - /// - [`COption::None`] if `predicate` returns `false`. - /// - /// This function works similar to [`Iterator::filter()`]. You can imagine - /// the `COption` being an iterator over one or zero elements. `filter()` - /// lets you decide which elements to keep. - /// - /// # Examples - /// - /// ```ignore - /// fn is_even(n: &i32) -> bool { - /// n % 2 == 0 - /// } - /// - /// assert_eq!(COption::None.filter(is_even), COption::None); - /// assert_eq!(COption::Some(3).filter(is_even), COption::None); - /// assert_eq!(COption::Some(4).filter(is_even), COption::Some(4)); - /// ``` - /// - /// [`COption::None`]: #variant.COption::None - /// [`COption::Some(t)`]: #variant.COption::Some - /// [`Iterator::filter()`]: ../../std/iter/trait.Iterator.html#method.filter - #[inline] - pub fn filter bool>(self, predicate: P) -> Self { - if let COption::Some(x) = self { - if predicate(&x) { - return COption::Some(x); - } - } - COption::None - } - - /// Returns the option if it contains a value, otherwise returns `optb`. - /// - /// Arguments passed to `or` are eagerly evaluated; if you are passing the - /// result of a function call, it is recommended to use [`or_else`], which is - /// lazily evaluated. - /// - /// [`or_else`]: #method.or_else - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some(2); - /// let y = COption::None; - /// assert_eq!(x.or(y), COption::Some(2)); - /// - /// let x = COption::None; - /// let y = COption::Some(100); - /// assert_eq!(x.or(y), COption::Some(100)); - /// - /// let x = COption::Some(2); - /// let y = COption::Some(100); - /// assert_eq!(x.or(y), COption::Some(2)); - /// - /// let x: COption = COption::None; - /// let y = COption::None; - /// assert_eq!(x.or(y), COption::None); - /// ``` - #[inline] - pub fn or(self, optb: COption) -> COption { - match self { - COption::Some(_) => self, - COption::None => optb, - } - } - - /// Returns the option if it contains a value, otherwise calls `f` and - /// returns the result. - /// - /// # Examples - /// - /// ```ignore - /// fn nobody() -> COption<&'static str> { COption::None } - /// fn vikings() -> COption<&'static str> { COption::Some("vikings") } - /// - /// assert_eq!(COption::Some("barbarians").or_else(vikings), COption::Some("barbarians")); - /// assert_eq!(COption::None.or_else(vikings), COption::Some("vikings")); - /// assert_eq!(COption::None.or_else(nobody), COption::None); - /// ``` - #[inline] - pub fn or_else COption>(self, f: F) -> COption { - match self { - COption::Some(_) => self, - COption::None => f(), - } - } - - /// Returns [`COption::Some`] if exactly one of `self`, `optb` is [`COption::Some`], otherwise returns [`COption::None`]. - /// - /// [`COption::Some`]: #variant.COption::Some - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some(2); - /// let y: COption = COption::None; - /// assert_eq!(x.xor(y), COption::Some(2)); - /// - /// let x: COption = COption::None; - /// let y = COption::Some(2); - /// assert_eq!(x.xor(y), COption::Some(2)); - /// - /// let x = COption::Some(2); - /// let y = COption::Some(2); - /// assert_eq!(x.xor(y), COption::None); - /// - /// let x: COption = COption::None; - /// let y: COption = COption::None; - /// assert_eq!(x.xor(y), COption::None); - /// ``` - #[inline] - pub fn xor(self, optb: COption) -> COption { - match (self, optb) { - (COption::Some(a), COption::None) => COption::Some(a), - (COption::None, COption::Some(b)) => COption::Some(b), - _ => COption::None, - } - } - - ///////////////////////////////////////////////////////////////////////// - // Entry-like operations to insert if COption::None and return a reference - ///////////////////////////////////////////////////////////////////////// - - /// Inserts `v` into the option if it is [`COption::None`], then - /// returns a mutable reference to the contained value. - /// - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let mut x = COption::None; - /// - /// { - /// let y: &mut u32 = x.get_or_insert(5); - /// assert_eq!(y, &5); - /// - /// *y = 7; - /// } - /// - /// assert_eq!(x, COption::Some(7)); - /// ``` - #[inline] - pub fn get_or_insert(&mut self, v: T) -> &mut T { - self.get_or_insert_with(|| v) - } - - /// Inserts a value computed from `f` into the option if it is [`COption::None`], then - /// returns a mutable reference to the contained value. - /// - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let mut x = COption::None; - /// - /// { - /// let y: &mut u32 = x.get_or_insert_with(|| 5); - /// assert_eq!(y, &5); - /// - /// *y = 7; - /// } - /// - /// assert_eq!(x, COption::Some(7)); - /// ``` - #[inline] - pub fn get_or_insert_with T>(&mut self, f: F) -> &mut T { - if let COption::None = *self { - *self = COption::Some(f()) - } - - match *self { - COption::Some(ref mut v) => v, - COption::None => unsafe { hint::unreachable_unchecked() }, - } - } - - ///////////////////////////////////////////////////////////////////////// - // Misc - ///////////////////////////////////////////////////////////////////////// - - /// Replaces the actual value in the option by the value given in parameter, - /// returning the old value if present, - /// leaving a [`COption::Some`] in its place without deinitializing either one. - /// - /// [`COption::Some`]: #variant.COption::Some - /// - /// # Examples - /// - /// ```ignore - /// let mut x = COption::Some(2); - /// let old = x.replace(5); - /// assert_eq!(x, COption::Some(5)); - /// assert_eq!(old, COption::Some(2)); - /// - /// let mut x = COption::None; - /// let old = x.replace(3); - /// assert_eq!(x, COption::Some(3)); - /// assert_eq!(old, COption::None); - /// ``` - #[inline] - pub fn replace(&mut self, value: T) -> COption { - mem::replace(self, COption::Some(value)) - } -} - -impl COption<&T> { - /// Maps an `COption<&T>` to an `COption` by copying the contents of the - /// option. - /// - /// # Examples - /// - /// ```ignore - /// let x = 12; - /// let opt_x = COption::Some(&x); - /// assert_eq!(opt_x, COption::Some(&12)); - /// let copied = opt_x.copied(); - /// assert_eq!(copied, COption::Some(12)); - /// ``` - pub fn copied(self) -> COption { - self.map(|&t| t) - } -} - -impl COption<&mut T> { - /// Maps an `COption<&mut T>` to an `COption` by copying the contents of the - /// option. - /// - /// # Examples - /// - /// ```ignore - /// let mut x = 12; - /// let opt_x = COption::Some(&mut x); - /// assert_eq!(opt_x, COption::Some(&mut 12)); - /// let copied = opt_x.copied(); - /// assert_eq!(copied, COption::Some(12)); - /// ``` - pub fn copied(self) -> COption { - self.map(|&mut t| t) - } -} - -impl COption<&T> { - /// Maps an `COption<&T>` to an `COption` by cloning the contents of the - /// option. - /// - /// # Examples - /// - /// ```ignore - /// let x = 12; - /// let opt_x = COption::Some(&x); - /// assert_eq!(opt_x, COption::Some(&12)); - /// let cloned = opt_x.cloned(); - /// assert_eq!(cloned, COption::Some(12)); - /// ``` - pub fn cloned(self) -> COption { - self.map(|t| t.clone()) - } -} - -impl COption<&mut T> { - /// Maps an `COption<&mut T>` to an `COption` by cloning the contents of the - /// option. - /// - /// # Examples - /// - /// ```ignore - /// let mut x = 12; - /// let opt_x = COption::Some(&mut x); - /// assert_eq!(opt_x, COption::Some(&mut 12)); - /// let cloned = opt_x.cloned(); - /// assert_eq!(cloned, COption::Some(12)); - /// ``` - pub fn cloned(self) -> COption { - self.map(|t| t.clone()) - } -} - -impl COption { - /// Returns the contained value or a default - /// - /// Consumes the `self` argument then, if [`COption::Some`], returns the contained - /// value, otherwise if [`COption::None`], returns the [default value] for that - /// type. - /// - /// # Examples - /// - /// Converts a string to an integer, turning poorly-formed strings - /// into 0 (the default value for integers). [`parse`] converts - /// a string to any other type that implements [`FromStr`], returning - /// [`COption::None`] on error. - /// - /// ```ignore - /// let good_year_from_input = "1909"; - /// let bad_year_from_input = "190blarg"; - /// let good_year = good_year_from_input.parse().ok().unwrap_or_default(); - /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default(); - /// - /// assert_eq!(1909, good_year); - /// assert_eq!(0, bad_year); - /// ``` - /// - /// [`COption::Some`]: #variant.COption::Some - /// [`COption::None`]: #variant.COption::None - /// [default value]: ../default/trait.Default.html#tymethod.default - /// [`parse`]: ../../std/primitive.str.html#method.parse - /// [`FromStr`]: ../../std/str/trait.FromStr.html - #[inline] - pub fn unwrap_or_default(self) -> T { - match self { - COption::Some(x) => x, - COption::None => Default::default(), - } - } -} - -impl COption { - /// Converts from `COption` (or `&COption`) to `COption<&T::Target>`. - /// - /// Leaves the original COption in-place, creating a new one with a reference - /// to the original one, additionally coercing the contents via [`Deref`]. - /// - /// [`Deref`]: ../../std/ops/trait.Deref.html - /// - /// # Examples - /// - /// ```ignore - /// #![feature(inner_deref)] - /// - /// let x: COption = COption::Some("hey".to_owned()); - /// assert_eq!(x.as_deref(), COption::Some("hey")); - /// - /// let x: COption = COption::None; - /// assert_eq!(x.as_deref(), COption::None); - /// ``` - pub fn as_deref(&self) -> COption<&T::Target> { - self.as_ref().map(|t| t.deref()) - } -} - -impl COption { - /// Converts from `COption` (or `&mut COption`) to `COption<&mut T::Target>`. - /// - /// Leaves the original `COption` in-place, creating a new one containing a mutable reference to - /// the inner type's `Deref::Target` type. - /// - /// # Examples - /// - /// ```ignore - /// #![feature(inner_deref)] - /// - /// let mut x: COption = COption::Some("hey".to_owned()); - /// assert_eq!(x.as_deref_mut().map(|x| { - /// x.make_ascii_uppercase(); - /// x - /// }), COption::Some("HEY".to_owned().as_mut_str())); - /// ``` - pub fn as_deref_mut(&mut self) -> COption<&mut T::Target> { - self.as_mut().map(|t| t.deref_mut()) - } -} - -impl COption> { - /// Transposes an `COption` of a [`Result`] into a [`Result`] of an `COption`. - /// - /// [`COption::None`] will be mapped to [`Ok`]`(`[`COption::None`]`)`. - /// [`COption::Some`]`(`[`Ok`]`(_))` and [`COption::Some`]`(`[`Err`]`(_))` will be mapped to - /// [`Ok`]`(`[`COption::Some`]`(_))` and [`Err`]`(_)`. - /// - /// [`COption::None`]: #variant.COption::None - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`COption::Some`]: #variant.COption::Some - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ```ignore - /// #[derive(Debug, Eq, PartialEq)] - /// struct COption::SomeErr; - /// - /// let x: Result, COption::SomeErr> = Ok(COption::Some(5)); - /// let y: COption> = COption::Some(Ok(5)); - /// assert_eq!(x, y.transpose()); - /// ``` - #[inline] - pub fn transpose(self) -> Result, E> { - match self { - COption::Some(Ok(x)) => Ok(COption::Some(x)), - COption::Some(Err(e)) => Err(e), - COption::None => Ok(COption::None), - } - } -} - -// This is a separate function to reduce the code size of .expect() itself. -#[inline(never)] -#[cold] -fn expect_failed(msg: &str) -> ! { - panic!("{}", msg) -} - -// // This is a separate function to reduce the code size of .expect_none() itself. -// #[inline(never)] -// #[cold] -// fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! { -// panic!("{}: {:?}", msg, value) -// } - -///////////////////////////////////////////////////////////////////////////// -// Trait implementations -///////////////////////////////////////////////////////////////////////////// - -impl Clone for COption { - #[inline] - fn clone(&self) -> Self { - match self { - COption::Some(x) => COption::Some(x.clone()), - COption::None => COption::None, - } - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - match (self, source) { - (COption::Some(to), COption::Some(from)) => to.clone_from(from), - (to, from) => *to = from.clone(), - } - } -} - -impl Default for COption { - /// Returns [`COption::None`][COption::COption::None]. - /// - /// # Examples - /// - /// ```ignore - /// let opt: COption = COption::default(); - /// assert!(opt.is_none()); - /// ``` - #[inline] - fn default() -> COption { - COption::None - } -} - -impl From for COption { - fn from(val: T) -> COption { - COption::Some(val) - } -} - -impl<'a, T> From<&'a COption> for COption<&'a T> { - fn from(o: &'a COption) -> COption<&'a T> { - o.as_ref() - } -} - -impl<'a, T> From<&'a mut COption> for COption<&'a mut T> { - fn from(o: &'a mut COption) -> COption<&'a mut T> { - o.as_mut() - } -} - -impl COption> { - /// Converts from `COption>` to `COption` - /// - /// # Examples - /// Basic usage: - /// ```ignore - /// #![feature(option_flattening)] - /// let x: COption> = COption::Some(COption::Some(6)); - /// assert_eq!(COption::Some(6), x.flatten()); - /// - /// let x: COption> = COption::Some(COption::None); - /// assert_eq!(COption::None, x.flatten()); - /// - /// let x: COption> = COption::None; - /// assert_eq!(COption::None, x.flatten()); - /// ``` - /// Flattening once only removes one level of nesting: - /// ```ignore - /// #![feature(option_flattening)] - /// let x: COption>> = COption::Some(COption::Some(COption::Some(6))); - /// assert_eq!(COption::Some(COption::Some(6)), x.flatten()); - /// assert_eq!(COption::Some(6), x.flatten().flatten()); - /// ``` - #[inline] - pub fn flatten(self) -> COption { - self.and_then(convert::identity) - } -} diff --git a/program/src/processor.rs b/program/src/processor.rs deleted file mode 100644 index 238c0d1..0000000 --- a/program/src/processor.rs +++ /dev/null @@ -1,2349 +0,0 @@ -//! Program state processor - -#![cfg(feature = "program")] - -use crate::{ - error::TokenError, - instruction::{is_valid_signer_index, TokenInstruction}, - option::COption, - state::{self, Account, Mint, Multisig}, -}; -use num_traits::FromPrimitive; -use solana_sdk::{ - account_info::{next_account_info, AccountInfo}, - decode_error::DecodeError, - entrypoint::ProgramResult, - info, - program_error::{PrintProgramError, ProgramError}, - pubkey::Pubkey, -}; -use std::mem::size_of; - -/// Program state handler. -pub struct Processor {} -impl Processor { - /// Processes an [InitializeMint](enum.TokenInstruction.html) instruction. - pub fn process_initialize_mint( - accounts: &[AccountInfo], - amount: u64, - decimals: u8, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - - let mut mint_info_data = mint_info.data.borrow_mut(); - let mut mint: &mut Mint = state::unpack_unchecked(&mut mint_info_data)?; - if mint.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } - - let owner = if amount != 0 { - let dest_account_info = next_account_info(account_info_iter)?; - let mut dest_account_data = dest_account_info.data.borrow_mut(); - let mut dest_account: &mut Account = state::unpack(&mut dest_account_data)?; - - if mint_info.key != &dest_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - dest_account.amount = amount; - - if let Ok(owner_info) = next_account_info(account_info_iter) { - COption::Some(*owner_info.key) - } else { - COption::None - } - } else if let Ok(owner_info) = next_account_info(account_info_iter) { - COption::Some(*owner_info.key) - } else { - return Err(TokenError::OwnerRequiredIfNoInitialSupply.into()); - }; - - mint.owner = owner; - mint.decimals = decimals; - mint.is_initialized = true; - - Ok(()) - } - - /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let new_account_info = next_account_info(account_info_iter)?; - let mint_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - - let mut new_account_data = new_account_info.data.borrow_mut(); - let mut account: &mut Account = state::unpack_unchecked(&mut new_account_data)?; - if account.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } - - account.mint = *mint_info.key; - account.owner = *owner_info.key; - account.delegate = COption::None; - account.delegated_amount = 0; - account.is_initialized = true; - if *mint_info.key == crate::native_mint::id() { - account.is_native = true; - account.amount = new_account_info.lamports(); - } else { - account.is_native = false; - account.amount = 0; - }; - - Ok(()) - } - - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. - pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let multisig_info = next_account_info(account_info_iter)?; - let mut multisig_account_data = multisig_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack_unchecked(&mut multisig_account_data)?; - if multisig.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } - - let signer_infos = account_info_iter.as_slice(); - multisig.m = m; - multisig.n = signer_infos.len() as u8; - if !is_valid_signer_index(multisig.n as usize) { - return Err(TokenError::InvalidNumberOfProvidedSigners.into()); - } - if !is_valid_signer_index(multisig.m as usize) { - return Err(TokenError::InvalidNumberOfRequiredSigners.into()); - } - for (i, signer_info) in signer_infos.iter().enumerate() { - multisig.signers[i] = *signer_info.key; - } - multisig.is_initialized = true; - - Ok(()) - } - - /// Processes a [Transfer](enum.TokenInstruction.html) instruction. - pub fn process_transfer( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - let dest_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - let mut source_data = source_account_info.data.borrow_mut(); - let mut source_account: &mut Account = state::unpack(&mut source_data)?; - let mut dest_data = dest_account_info.data.borrow_mut(); - let mut dest_account: &mut Account = state::unpack(&mut dest_data)?; - - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if source_account.mint != dest_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - match source_account.delegate { - COption::Some(ref delegate) if authority_info.key == delegate => { - Self::validate_owner( - program_id, - delegate, - authority_info, - account_info_iter.as_slice(), - )?; - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - source_account.delegated_amount -= amount; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } - } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, - }; - - source_account.amount -= amount; - dest_account.amount = dest_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - if source_account.is_native { - **source_account_info.lamports.borrow_mut() -= amount; - **dest_account_info.lamports.borrow_mut() += amount; - } - - Ok(()) - } - - /// Processes an [Approve](enum.TokenInstruction.html) instruction. - pub fn process_approve( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - - let mut source_data = source_account_info.data.borrow_mut(); - let mut source_account: &mut Account = state::unpack(&mut source_data)?; - let delegate_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - - Self::validate_owner( - program_id, - &source_account.owner, - owner_info, - account_info_iter.as_slice(), - )?; - - source_account.delegate = COption::Some(*delegate_info.key); - source_account.delegated_amount = amount; - - Ok(()) - } - - /// Processes an [Revoke](enum.TokenInstruction.html) instruction. - pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - - let mut source_data = source_account_info.data.borrow_mut(); - let mut source_account: &mut Account = state::unpack(&mut source_data)?; - let owner_info = next_account_info(account_info_iter)?; - - Self::validate_owner( - program_id, - &source_account.owner, - owner_info, - account_info_iter.as_slice(), - )?; - - source_account.delegate = COption::None; - source_account.delegated_amount = 0; - - Ok(()) - } - - /// Processes a [SetOwner](enum.TokenInstruction.html) instruction. - pub fn process_set_owner(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let account_info = next_account_info(account_info_iter)?; - let new_owner_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - if account_info.data_len() == size_of::() { - let mut account_data = account_info.data.borrow_mut(); - let mut account: &mut Account = state::unpack(&mut account_data)?; - - Self::validate_owner( - program_id, - &account.owner, - authority_info, - account_info_iter.as_slice(), - )?; - - account.owner = *new_owner_info.key; - } else if account_info.data_len() == size_of::() { - let mut account_data = account_info.data.borrow_mut(); - let mut mint: &mut Mint = state::unpack(&mut account_data)?; - - match mint.owner { - COption::Some(ref owner) => { - Self::validate_owner( - program_id, - owner, - authority_info, - account_info_iter.as_slice(), - )?; - } - COption::None => return Err(TokenError::FixedSupply.into()), - } - mint.owner = COption::Some(*new_owner_info.key); - } else { - return Err(ProgramError::InvalidArgument); - } - - Ok(()) - } - - /// Processes a [MintTo](enum.TokenInstruction.html) instruction. - pub fn process_mint_to( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let mint_info = next_account_info(account_info_iter)?; - let dest_account_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; - - let mut dest_account_data = dest_account_info.data.borrow_mut(); - let mut dest_account: &mut Account = state::unpack(&mut dest_account_data)?; - - if dest_account.is_native { - return Err(TokenError::NativeNotSupported.into()); - } - if mint_info.key != &dest_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - let mut mint_info_data = mint_info.data.borrow_mut(); - let mint: &mut Mint = state::unpack(&mut mint_info_data)?; - - match mint.owner { - COption::Some(owner) => { - Self::validate_owner(program_id, &owner, owner_info, account_info_iter.as_slice())?; - } - COption::None => { - return Err(TokenError::FixedSupply.into()); - } - } - - dest_account.amount = dest_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - Ok(()) - } - - /// Processes a [Burn](enum.TokenInstruction.html) instruction. - pub fn process_burn( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - ) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - let mut source_data = source_account_info.data.borrow_mut(); - let source_account: &mut Account = state::unpack(&mut source_data)?; - - if source_account.is_native { - return Err(TokenError::NativeNotSupported.into()); - } - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - - match source_account.delegate { - COption::Some(ref delegate) if authority_info.key == delegate => { - Self::validate_owner( - program_id, - delegate, - authority_info, - account_info_iter.as_slice(), - )?; - - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - source_account.delegated_amount -= amount; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } - } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, - } - - source_account.amount -= amount; - - Ok(()) - } - - /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. - pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let account_info_iter = &mut accounts.iter(); - let source_account_info = next_account_info(account_info_iter)?; - let dest_account_info = next_account_info(account_info_iter)?; - let authority_info = next_account_info(account_info_iter)?; - - let mut source_data = source_account_info.data.borrow_mut(); - let source_account: &mut Account = state::unpack(&mut source_data)?; - - if !source_account.is_native { - return Err(TokenError::NonNativeNotSupported.into()); - } - - Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?; - - **dest_account_info.lamports.borrow_mut() += source_account_info.lamports(); - **source_account_info.lamports.borrow_mut() = 0; - source_account.amount = 0; - - Ok(()) - } - - /// Processes an [Instruction](enum.Instruction.html). - pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { - let instruction = TokenInstruction::unpack(input)?; - - match instruction { - TokenInstruction::InitializeMint { amount, decimals } => { - info!("Instruction: InitializeMint"); - Self::process_initialize_mint(accounts, amount, decimals) - } - TokenInstruction::InitializeAccount => { - info!("Instruction: InitializeAccount"); - Self::process_initialize_account(accounts) - } - TokenInstruction::InitializeMultisig { m } => { - info!("Instruction: InitializeMultisig"); - Self::process_initialize_multisig(accounts, m) - } - TokenInstruction::Transfer { amount } => { - info!("Instruction: Transfer"); - Self::process_transfer(program_id, accounts, amount) - } - TokenInstruction::Approve { amount } => { - info!("Instruction: Approve"); - Self::process_approve(program_id, accounts, amount) - } - TokenInstruction::Revoke => { - info!("Instruction: Revoke"); - Self::process_revoke(program_id, accounts) - } - TokenInstruction::SetOwner => { - info!("Instruction: SetOwner"); - Self::process_set_owner(program_id, accounts) - } - TokenInstruction::MintTo { amount } => { - info!("Instruction: MintTo"); - Self::process_mint_to(program_id, accounts, amount) - } - TokenInstruction::Burn { amount } => { - info!("Instruction: Burn"); - Self::process_burn(program_id, accounts, amount) - } - TokenInstruction::CloseAccount => { - info!("Instruction: CloseAccount"); - Self::process_close_account(program_id, accounts) - } - } - } - - /// Validates owner(s) are present - pub fn validate_owner( - program_id: &Pubkey, - expected_owner: &Pubkey, - owner_account_info: &AccountInfo, - signers: &[AccountInfo], - ) -> ProgramResult { - if expected_owner != owner_account_info.key { - return Err(TokenError::OwnerMismatch.into()); - } - if program_id == owner_account_info.owner - && owner_account_info.data_len() == std::mem::size_of::() - { - let mut owner_data = owner_account_info.data.borrow_mut(); - let multisig: &mut Multisig = state::unpack(&mut owner_data)?; - let mut num_signers = 0; - for signer in signers.iter() { - if multisig.signers[0..multisig.n as usize].contains(signer.key) { - if !signer.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - num_signers += 1; - } - } - if num_signers < multisig.m { - return Err(ProgramError::MissingRequiredSignature); - } - } else if !owner_account_info.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - Ok(()) - } -} - -impl PrintProgramError for TokenError { - fn print(&self) - where - E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, - { - match self { - TokenError::InsufficientFunds => info!("Error: insufficient funds"), - TokenError::MintMismatch => info!("Error: Account not associated with this Mint"), - TokenError::OwnerMismatch => info!("Error: owner does not match"), - TokenError::FixedSupply => info!("Error: the total supply of this token is fixed"), - TokenError::AlreadyInUse => info!("Error: account or token already in use"), - TokenError::OwnerRequiredIfNoInitialSupply => { - info!("Error: An owner is required if supply is zero") - } - TokenError::InvalidNumberOfProvidedSigners => { - info!("Error: Invalid number of provided signers") - } - TokenError::InvalidNumberOfRequiredSigners => { - info!("Error: Invalid number of required signers") - } - TokenError::UninitializedState => info!("Error: State is uninitialized"), - TokenError::NativeNotSupported => { - info!("Error: Instruction does not support native tokens") - } - TokenError::NonNativeNotSupported => { - info!("Error: Instruction does not support non-native tokens") - } - TokenError::InvalidInstruction => info!("Error: Invalid instruction"), - TokenError::Overflow => info!("Error: Operation overflowed"), - } - } -} - -// Pull in syscall stubs when building for non-BPF targets -#[cfg(not(target_arch = "bpf"))] -solana_sdk::program_stubs!(); - -#[cfg(test)] -mod tests { - use super::*; - use crate::instruction::{ - approve, burn, close_account, initialize_account, initialize_mint, initialize_multisig, - mint_to, revoke, set_owner, transfer, MAX_SIGNERS, - }; - use solana_sdk::{ - account::Account as SolanaAccount, account_info::create_is_signer_account_infos, - clock::Epoch, instruction::Instruction, - }; - - fn pubkey_rand() -> Pubkey { - Pubkey::new(&rand::random::<[u8; 32]>()) - } - - fn do_process_instruction( - instruction: Instruction, - accounts: Vec<&mut SolanaAccount>, - ) -> ProgramResult { - let mut meta = instruction - .accounts - .iter() - .zip(accounts) - .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) - .collect::>(); - - let account_infos = create_is_signer_account_infos(&mut meta); - Processor::process(&instruction.program_id, &account_infos, &instruction.data) - } - - fn return_token_error_as_program_error() -> ProgramError { - TokenError::MintMismatch.into() - } - - #[test] - fn test_print_error() { - let error = return_token_error_as_program_error(); - error.print::(); - } - - #[test] - #[should_panic(expected = "Custom(1)")] - fn test_error_unwrap() { - Err::<(), ProgramError>(return_token_error_as_program_error()).unwrap(); - } - - #[test] - fn test_unique_account_sizes() { - assert_ne!(size_of::(), 0); - assert_ne!(size_of::(), size_of::()); - assert_ne!(size_of::(), size_of::()); - assert_ne!(size_of::(), 0); - assert_ne!(size_of::(), size_of::()); - assert_ne!(size_of::(), 0); - } - - #[test] - fn test_initialize_mint() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); - - // account not created - assert_eq!( - Err(TokenError::UninitializedState.into()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), - vec![&mut mint_account, &mut account_account] - ) - ); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut owner_account, &mut mint_account], - ) - .unwrap(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), - vec![&mut mint_account, &mut account_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut owner_account, &mut mint_account], - ) - .unwrap(); - - // mismatch account - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - initialize_mint(&program_id, &mint2_key, Some(&account2_key), None, 1000, 2) - .unwrap(), - vec![&mut mint2_account, &mut account2_account] - ) - ); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), - vec![&mut mint_account, &mut account_account] - ) - ); - } - - #[test] - fn test_initialize_mint_account() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_transfer() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); - let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); - let delegate_key = pubkey_rand(); - let mut delegate_account = SolanaAccount::default(); - let mismatch_key = pubkey_rand(); - let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), - vec![&mut mint_account, &mut account_account], - ) - .unwrap(); - - // missing signer - let mut instruction = transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // mismatch mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &mismatch_key, - &owner_key, - &[], - 1000 - ) - .unwrap(), - vec![ - &mut account_account, - &mut mismatch_account, - &mut owner_account, - ], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner2_key, - &[], - 1000 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // transfer - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // transfer half back - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // transfer rest - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // transfer via delegate - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - .unwrap(); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - - // transfer rest - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 900, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds in source account via delegate - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - } - - #[test] - fn test_mintable_token_with_zero_supply() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut owner_account, &mut mint_account], - ) - .unwrap(); - - // create mint-able token without owner - let mut instruction = - initialize_mint(&program_id, &mint_key, None, Some(&owner_key), 0, 2).unwrap(); - instruction.accounts.pop(); - assert_eq!( - Err(TokenError::OwnerRequiredIfNoInitialSupply.into()), - do_process_instruction(instruction, vec![&mut mint_account]) - ); - - // create mint-able token with zero supply - let amount = 0; - let decimals = 2; - do_process_instruction( - initialize_mint( - &program_id, - &mint_key, - None, - Some(&owner_key), - amount, - decimals, - ) - .unwrap(), - vec![&mut mint_account, &mut account_account], - ) - .unwrap(); - let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - assert_eq!( - *mint, - Mint { - owner: COption::Some(owner_key), - decimals, - is_initialized: true, - } - ); - - // mint to - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(dest_account.amount, 42); - } - - #[test] - fn test_approve() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); - let delegate_key = pubkey_rand(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut owner_account, &mut mint_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut owner_account, &mut mint_account], - ) - .unwrap(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), - vec![&mut mint_account, &mut account_account], - ) - .unwrap(); - - // missing signer - let mut instruction = approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // no owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner2_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner2_account, - ], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // revoke delegate - do_process_instruction( - revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - } - - #[test] - fn test_set_owner() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); - let mut owner2_account = SolanaAccount::default(); - let owner3_key = pubkey_rand(); - let mut owner3_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); - - // invalid account - assert_eq!( - Err(TokenError::UninitializedState.into()), - do_process_instruction( - set_owner(&program_id, &account_key, &owner2_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut owner2_account, - &mut owner_account, - ], - ) - ); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_owner(&program_id, &account_key, &owner_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut owner_account, - &mut owner2_account, - ], - ) - ); - - // owner did not sign - let mut instruction = - set_owner(&program_id, &account_key, &owner2_key, &owner_key, &[]).unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut owner2_account, - &mut owner_account, - ], - ) - ); - - // set owner - do_process_instruction( - set_owner(&program_id, &account_key, &owner2_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut owner2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // create new mint with owner - do_process_instruction( - initialize_mint( - &program_id, - &mint_key, - Some(&account_key), - Some(&owner_key), - 1000, - 2, - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // wrong account - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_owner(&program_id, &mint_key, &owner3_key, &owner2_key, &[]).unwrap(), - vec![&mut mint_account, &mut owner3_account, &mut owner2_account], - ) - ); - - // owner did not sign - let mut instruction = - set_owner(&program_id, &mint_key, &owner2_key, &owner_key, &[]).unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![&mut mint_account, &mut owner2_account, &mut owner_account], - ) - ); - - // set owner - do_process_instruction( - set_owner(&program_id, &mint_key, &owner2_key, &owner_key, &[]).unwrap(), - vec![&mut mint_account, &mut owner2_account, &mut owner_account], - ) - .unwrap(); - - // create new mint without owner - do_process_instruction( - initialize_mint(&program_id, &mint2_key, Some(&account2_key), None, 1000, 2).unwrap(), - vec![&mut mint2_account, &mut account2_account], - ) - .unwrap(); - - // set owner for non-mint-able token - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_owner(&program_id, &mint2_key, &owner2_key, &owner_key, &[]).unwrap(), - vec![&mut mint_account, &mut owner2_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_mint_to() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); - let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); - let mismatch_key = pubkey_rand(); - let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); - let uninitialized_key = pubkey_rand(); - let mut uninitialized_account = SolanaAccount::new(0, size_of::(), &program_id); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // create new mint with owner - do_process_instruction( - initialize_mint( - &program_id, - &mint_key, - Some(&account_key), - Some(&owner_key), - 1000, - 2, - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // mint to - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - .unwrap(); - - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - let dest_account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert_eq!(dest_account.amount, 42); - - // missing signer - let mut instruction = - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - ); - - // mismatch account - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut mismatch_account, &mut owner_account], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // uninitialized destination account - assert_eq!( - Err(TokenError::UninitializedState.into()), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &uninitialized_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![ - &mut mint_account, - &mut uninitialized_account, - &mut owner_account, - ], - ) - ); - } - - #[test] - fn test_burn() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); - let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); - let delegate_key = pubkey_rand(); - let mut delegate_account = SolanaAccount::default(); - let mismatch_key = pubkey_rand(); - let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, Some(&account_key), None, 1000, 2).unwrap(), - vec![&mut mint_account, &mut account_account], - ) - .unwrap(); - - // missing signer - let mut instruction = burn(&program_id, &account_key, &delegate_key, &[], 42).unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - instruction, - vec![&mut account_account, &mut delegate_account], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn(&program_id, &account_key, &owner2_key, &[], 42).unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - ); - - // burn - do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 84, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // not a delegate of source account - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // burn via delegate - do_process_instruction( - burn(&program_id, &account_key, &delegate_key, &[], 84).unwrap(), - vec![&mut account_account, &mut delegate_account], - ) - .unwrap(); - - // match - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42 - 84); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn(&program_id, &account_key, &delegate_key, &[], 100).unwrap(), - vec![&mut account_account, &mut delegate_account], - ) - ); - } - - #[test] - fn test_multisig() { - let program_id = pubkey_rand(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - let account_key = pubkey_rand(); - let mut account = SolanaAccount::new(0, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let multisig_key = pubkey_rand(); - let mut multisig_account = SolanaAccount::new(0, size_of::(), &program_id); - let multisig_delegate_key = pubkey_rand(); - let mut multisig_delegate_account = - SolanaAccount::new(0, size_of::(), &program_id); - let signer_keys = vec![pubkey_rand(); MAX_SIGNERS]; - let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().map(|key| key).collect(); - let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; - - // single signer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account, - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // multiple signer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig( - &program_id, - &multisig_delegate_key, - &signer_key_refs, - MAX_SIGNERS as u8, - ) - .unwrap(), - vec![ - &mut multisig_delegate_account, - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // create account with multisig owner - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), - vec![&mut account, &mut mint_account, &mut multisig_account], - ) - .unwrap(); - - // create another account with multisig owner - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &mint_key, - &multisig_delegate_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut multisig_account, - ], - ) - .unwrap(); - - // create new m int with multisig owner - do_process_instruction( - initialize_mint( - &program_id, - &mint_key, - Some(&account_key), - Some(&multisig_key), - 1000, - 2, - ) - .unwrap(), - vec![&mut mint_account, &mut account, &mut multisig_account], - ) - .unwrap(); - - // approve - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - approve( - &program_id, - &account_key, - &multisig_delegate_key, - &multisig_key, - &[&signer_keys[0]], - 100, - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_delegate_account, - &mut multisig_account, - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // transfer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut account2_account, - &mut multisig_account, - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // transfer via delegate - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &multisig_delegate_key, - &signer_key_refs, - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut account2_account, - &mut multisig_delegate_account, - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // mint to - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut multisig_account, - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // burn - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - burn( - &program_id, - &account_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_account, - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // burn via delegate - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - burn( - &program_id, - &account_key, - &multisig_delegate_key, - &signer_key_refs, - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_delegate_account, - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // do SetOwner on mint - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - set_owner( - &program_id, - &mint_key, - &owner_key, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut mint_account, - &mut owner_account, - &mut multisig_account, - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // do SetOwner on account - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - set_owner( - &program_id, - &account_key, - &owner_key, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut account, - &mut owner_account, - &mut multisig_account, - &mut account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - } - - #[test] - fn test_validate_owner() { - let program_id = pubkey_rand(); - let owner_key = pubkey_rand(); - let mut signer_keys = [Pubkey::default(); MAX_SIGNERS]; - for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) { - *signer_key = pubkey_rand(); - } - let mut signer_lamports = 0; - let mut signer_data = vec![]; - let mut signers = vec![ - AccountInfo::new( - &owner_key, - true, - false, - &mut signer_lamports, - &mut signer_data, - &program_id, - false, - Epoch::default(), - ); - MAX_SIGNERS + 1 - ]; - for (signer, key) in signers.iter_mut().zip(&signer_keys) { - signer.key = key; - } - let mut lamports = 0; - let mut data = vec![0; size_of::()]; - let mut multisig: &mut Multisig = state::unpack_unchecked(&mut data).unwrap(); - multisig.m = MAX_SIGNERS as u8; - multisig.n = MAX_SIGNERS as u8; - multisig.signers = signer_keys; - multisig.is_initialized = true; - let owner_account_info = AccountInfo::new( - &owner_key, - false, - false, - &mut lamports, - &mut data, - &program_id, - false, - Epoch::default(), - ); - - // full 11 of 11 - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); - - // 1 of 11 - { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 1; - } - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); - - // 2:1 - { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 1; - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) - ); - - // 0:11 - { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 0; - multisig.n = 11; - } - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); - - // 2:11 but 0 provided - { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 11; - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &[]) - ); - // 2:11 but 1 provided - { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 11; - } - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[0..1]) - ); - - // 2:11, 2 from middle provided - { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 11; - } - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[5..7]) - .unwrap(); - - // 11:11, one is not a signer - { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 11; - } - signers[5].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) - ); - signers[5].is_signer = true; - } - - #[test] - fn test_close_account() { - let program_id = pubkey_rand(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(2, size_of::(), &program_id); - let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(2, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); - let mut owner2_account = SolanaAccount::default(); - - // uninitialized - assert_eq!( - Err(TokenError::UninitializedState.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - ); - - // initialize non-native account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account.amount, 2); - - // close non-native account - assert_eq!( - Err(TokenError::NonNativeNotSupported.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - ); - assert_eq!(account_account.lamports, 42); - - // close native account - do_process_instruction( - close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account2_account, - &mut account3_account, - &mut owner_account, - ], - ) - .unwrap(); - let account: &mut Account = state::unpack_unchecked(&mut account2_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account.amount, 0); - assert_eq!(account3_account.lamports, 4); - } - - #[test] - fn test_native_token() { - let program_id = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(2, size_of::(), &program_id); - let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(2, 0, &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account.amount, 42); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account.amount, 2); - - // mint_to unsupported - assert_eq!( - Err(TokenError::NativeNotSupported.into()), - do_process_instruction( - mint_to( - &program_id, - &crate::native_mint::id(), - &account_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - - // burn unsupported - assert_eq!( - Err(TokenError::NativeNotSupported.into()), - do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // initialize native account - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 40, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account_account.lamports, 2); - assert_eq!(account.amount, 2); - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account2_account.lamports, 42); - assert_eq!(account.amount, 42); - - // close native account - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - .unwrap(); - let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account_account.lamports, 0); - assert_eq!(account.amount, 0); - assert_eq!(account3_account.lamports, 4); - } - - #[test] - fn test_overflow() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); - let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); - let owner_key = pubkey_rand(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); - let mut owner2_account = SolanaAccount::default(); - let mint_owner_key = pubkey_rand(); - let mut mint_owner_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); - - // create victim account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner2_account, - ], - ) - .unwrap(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, None, Some(&mint_owner_key), 0, 2).unwrap(), - vec![&mut mint_account, &mut mint_owner_account], - ) - .unwrap(); - - // mint the max to attacker - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &mint_owner_key, - &[], - 42, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint the max to victum - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // mint one more - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - ); - - // mint back to large amount - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - account.amount = 0; - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // transfer to burn victim - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner2_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner2_account, - ], - ) - ); - } -} diff --git a/program/src/state.rs b/program/src/state.rs deleted file mode 100644 index 3b63f4f..0000000 --- a/program/src/state.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! State transition types - -use crate::{error::TokenError, instruction::MAX_SIGNERS, option::COption}; -use solana_sdk::{program_error::ProgramError, pubkey::Pubkey}; -use std::mem::size_of; - -/// Mint data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Mint { - /// Optional owner, used to mint new tokens. The owner may only - /// be provided during mint creation. If no owner is present then the mint - /// has a fixed supply and no further tokens may be minted. - pub owner: COption, - /// Number of base 10 digits to the right of the decimal place. - pub decimals: u8, - /// Is `true` if this structure has been initialized - pub is_initialized: bool, -} -impl IsInitialized for Mint { - fn is_initialized(&self) -> bool { - self.is_initialized - } -} - -/// Account data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Account { - /// The mint associated with this account - pub mint: Pubkey, - /// The owner of this account. - pub owner: Pubkey, - /// The amount of tokens this account holds. - pub amount: u64, - /// If `delegate` is `Some` then `delegated_amount` represents - /// the amount authorized by the delegate - pub delegate: COption, - /// Is `true` if this structure has been initialized - pub is_initialized: bool, - /// Is this a native token - pub is_native: bool, - /// The amount delegated - pub delegated_amount: u64, -} -impl IsInitialized for Account { - fn is_initialized(&self) -> bool { - self.is_initialized - } -} - -/// Multisignature data. -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct Multisig { - /// Number of signers required - pub m: u8, - /// Number of valid signers - pub n: u8, - /// Is `true` if this structure has been initialized - pub is_initialized: bool, - /// Signer public keys - pub signers: [Pubkey; MAX_SIGNERS], -} -impl IsInitialized for Multisig { - fn is_initialized(&self) -> bool { - self.is_initialized - } -} - -/// Check is a token state is initialized -pub trait IsInitialized { - /// Is initialized - fn is_initialized(&self) -> bool; -} - -/// Unpacks a token state from a bytes buffer while assuring that the state is initialized. -pub fn unpack(input: &mut [u8]) -> Result<&mut T, ProgramError> { - let mut_ref: &mut T = unpack_unchecked(input)?; - if !mut_ref.is_initialized() { - return Err(TokenError::UninitializedState.into()); - } - Ok(mut_ref) -} -/// Unpacks a token state from a bytes buffer without checking that the state is initialized. -pub fn unpack_unchecked(input: &mut [u8]) -> Result<&mut T, ProgramError> { - if input.len() != size_of::() { - return Err(ProgramError::InvalidAccountData); - } - #[allow(clippy::cast_ptr_alignment)] - Ok(unsafe { &mut *(&mut input[0] as *mut u8 as *mut T) }) -} From 83d9488261f74777806bc0d4f33d37ce57656ec9 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 26 Aug 2020 22:08:40 -0700 Subject: [PATCH 029/335] Relocate program2 into program --- program/Cargo.toml | 34 + program/Xargo.toml | 2 + program/build.rs | 65 + program/inc/token.h | 359 +++++ program/program-id.md | 1 + program/src/entrypoint.rs | 24 + program/src/error.rs | 71 + program/src/instruction.rs | 915 +++++++++++ program/src/lib.rs | 28 + program/src/native_mint.rs | 24 + program/src/option.rs | 1112 +++++++++++++ program/src/processor.rs | 3128 ++++++++++++++++++++++++++++++++++++ program/src/state.rs | 122 ++ 13 files changed, 5885 insertions(+) create mode 100644 program/Cargo.toml create mode 100644 program/Xargo.toml create mode 100644 program/build.rs create mode 100644 program/inc/token.h create mode 100644 program/program-id.md create mode 100644 program/src/entrypoint.rs create mode 100644 program/src/error.rs create mode 100644 program/src/instruction.rs create mode 100644 program/src/lib.rs create mode 100644 program/src/native_mint.rs create mode 100644 program/src/option.rs create mode 100644 program/src/processor.rs create mode 100644 program/src/state.rs diff --git a/program/Cargo.toml b/program/Cargo.toml new file mode 100644 index 0000000..e112088 --- /dev/null +++ b/program/Cargo.toml @@ -0,0 +1,34 @@ + +# Note: This crate must be built using do.sh + +[package] +name = "spl-token" +version = "1.1.0" +description = "Solana Program Library Token" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana-program-library" +license = "Apache-2.0" +edition = "2018" +exclude = ["js/**"] + +[features] +no-entrypoint = [] +skip-no-mangle = ["solana-sdk/skip-no-mangle"] +program = ["solana-sdk/program"] +default = ["solana-sdk/default"] + +[dependencies] +num-derive = "0.3" +num-traits = "0.2" +remove_dir_all = "=0.5.0" +solana-sdk = { version = "1.3.4", default-features = false, optional = true } +thiserror = "1.0" + +[dev-dependencies] +rand = { version = "0.7.0"} + +[build-dependencies] +cbindgen = "=0.14.2" + +[lib] +crate-type = ["cdylib", "lib"] diff --git a/program/Xargo.toml b/program/Xargo.toml new file mode 100644 index 0000000..1744f09 --- /dev/null +++ b/program/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] \ No newline at end of file diff --git a/program/build.rs b/program/build.rs new file mode 100644 index 0000000..4862075 --- /dev/null +++ b/program/build.rs @@ -0,0 +1,65 @@ +extern crate cbindgen; + +use std::env; + +fn main() { + println!("cargo:rerun-if-env-changed=SPL_CBINDGEN"); + println!("cargo:rerun-if-changed=inc/token.h"); + if std::path::Path::new("inc/token.h").exists() && env::var("SPL_CBINDGEN").is_err() { + return; + } + + println!("cargo:warning=Generating inc/token.h"); + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let config = cbindgen::Config { + header: Some("/* Autogenerated SPL Token program C Bindings */".to_string()), + after_includes: Some(format!( + "{}{}{}", + format!( + "\n#define TOKEN_MAJOR_VERSION {}", + env!("CARGO_PKG_VERSION_MAJOR") + ), + format!( + "\n#define TOKEN_MINOR_VERSION {}", + env!("CARGO_PKG_VERSION_MINOR") + ), + format!( + "\n#define TOKEN_PATCH_VERSION {}", + env!("CARGO_PKG_VERSION_PATCH") + ) + )), + language: cbindgen::Language::C, + line_length: 80, + style: cbindgen::Style::Both, + tab_width: 4, + cpp_compat: true, + pragma_once: true, + enumeration: cbindgen::EnumConfig { + prefix_with_name: true, + ..cbindgen::EnumConfig::default() + }, + export: cbindgen::ExportConfig { + prefix: Some("Token_".to_string()), + include: vec![ + "TokenInstruction".to_string(), + "Mint".to_string(), + "Account".to_string(), + "Multisig".to_string(), + ], + exclude: vec!["DECIMALS".to_string()], + ..cbindgen::ExportConfig::default() + }, + parse: cbindgen::ParseConfig { + parse_deps: true, + include: Some(vec!["solana-sdk".to_string()]), + ..cbindgen::ParseConfig::default() + }, + ..cbindgen::Config::default() + }; + cbindgen::Builder::new() + .with_crate(crate_dir) + .with_config(config) + .generate() + .unwrap() + .write_to_file("inc/token.h"); +} diff --git a/program/inc/token.h b/program/inc/token.h new file mode 100644 index 0000000..38222c0 --- /dev/null +++ b/program/inc/token.h @@ -0,0 +1,359 @@ +/* Autogenerated SPL Token program C Bindings */ + +#pragma once + +#include +#include +#include +#include + +#define TOKEN_MAJOR_VERSION 1 +#define TOKEN_MINOR_VERSION 1 +#define TOKEN_PATCH_VERSION 0 + +/** + * Maximum number of multisignature signers (max N) + */ +#define Token_MAX_SIGNERS 11 + +/** + * Minimum number of multisignature signers (min N) + */ +#define Token_MIN_SIGNERS 1 + +/** + * Instructions supported by the token program. + */ +typedef enum Token_TokenInstruction_Tag { + /** + * Initializes a new mint and optionally deposits all the newly minted tokens in an account. + * + * The `InitializeMint` instruction requires no signers and MUST be included within + * the same Transaction as the system program's `CreateInstruction` that creates the account + * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * + * Accounts expected by this instruction: + * + * 0. `[writable]` The mint to initialize. + * 1. + * * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. + * * If supply is zero: `[]` The owner/multisignature of the mint. + * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if + * present then further minting is supported. + * + */ + Token_TokenInstruction_InitializeMint, + /** + * Initializes a new account to hold tokens. If this account is associated with the native mint + * then the token balance of the initialized account will be equal to the amount of SOL in the account. + * + * The `InitializeAccount` instruction requires no signers and MUST be included within + * the same Transaction as the system program's `CreateInstruction` that creates the account + * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * + * Accounts expected by this instruction: + * + * 0. `[writable]` The account to initialize. + * 1. `[]` The mint this account will be associated with. + * 2. `[]` The new account's owner/multisignature. + */ + Token_TokenInstruction_InitializeAccount, + /** + * Initializes a multisignature account with N provided signers. + * + * Multisignature accounts can used in place of any single owner/delegate accounts in any + * token instruction that require an owner/delegate to be present. The variant field represents the + * number of signers (M) required to validate this multisignature account. + * + * The `InitializeMultisig` instruction requires no signers and MUST be included within + * the same Transaction as the system program's `CreateInstruction` that creates the account + * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * + * Accounts expected by this instruction: + * + * 0. `[writable]` The multisignature account to initialize. + * 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + */ + Token_TokenInstruction_InitializeMultisig, + /** + * Transfers tokens from one account to another either directly or via a delegate. If this + * account is associated with the native mint then equal amounts of SOL and Tokens will be + * transferred to the destination account. + * + * Accounts expected by this instruction: + * + * * Single owner/delegate + * 0. `[writable]` The source account. + * 1. `[writable]` The destination account. + * 2. '[signer]' The source account's owner/delegate. + * + * * Multisignature owner/delegate + * 0. `[writable]` The source account. + * 1. `[writable]` The destination account. + * 2. '[]' The source account's multisignature owner/delegate. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_Transfer, + /** + * Approves a delegate. A delegate is given the authority over + * tokens on behalf of the source account's owner. + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The source account. + * 1. `[]` The delegate. + * 2. `[signer]` The source account owner. + * + * * Multisignature owner + * 0. `[writable]` The source account. + * 1. `[]` The delegate. + * 2. '[]' The source account's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts + */ + Token_TokenInstruction_Approve, + /** + * Revokes the delegate's authority. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The source account. + * 1. `[signer]` The source account owner. + * + * * Multisignature owner + * 0. `[writable]` The source account. + * 1. '[]' The source account's multisignature owner. + * 2. ..2+M '[signer]' M signer accounts + */ + Token_TokenInstruction_Revoke, + /** + * Sets a new owner of a mint or account. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The mint or account to change the owner of. + * 1. `[]` The new owner/delegate/multisignature. + * 2. `[signer]` The owner of the mint or account. + * + * * Multisignature owner + * 0. `[writable]` The mint or account to change the owner of. + * 1. `[]` The new owner/delegate/multisignature. + * 2. `[]` The mint's or account's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts + */ + Token_TokenInstruction_SetOwner, + /** + * Mints new tokens to an account. The native mint does not support minting. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The mint. + * 1. `[writable]` The account to mint tokens to. + * 2. `[signer]` The mint's owner. + * + * * Multisignature owner + * 0. `[writable]` The mint. + * 1. `[writable]` The account to mint tokens to. + * 2. `[]` The mint's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_MintTo, + /** + * Burns tokens by removing them from an account. `Burn` does not support accounts + * associated with the native mint, use `CloseAccount` instead. + * + * Accounts expected by this instruction: + * + * * Single owner/delegate + * 0. `[writable]` The account to burn from. + * 1. `[signer]` The account's owner/delegate. + * + * * Multisignature owner/delegate + * 0. `[writable]` The account to burn from. + * 1. `[]` The account's multisignature owner/delegate. + * 2. ..2+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_Burn, + /** + * Close an account by transferring all its SOL to the destination account. + * Non-native accounts may only be closed if its token amount is zero. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The account to close. + * 1. '[writable]' The destination account. + * 2. `[signer]` The account's owner. + * + * * Multisignature owner + * 0. `[writable]` The account to close. + * 1. '[writable]' The destination account. + * 2. `[]` The account's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_CloseAccount, +} Token_TokenInstruction_Tag; + +typedef struct Token_TokenInstruction_Token_InitializeMint_Body { + /** + * Initial amount of tokens to mint. + */ + uint64_t amount; + /** + * Number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_InitializeMint_Body; + +typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { + /** + * The number of signers (M) required to validate this multisignature account. + */ + uint8_t m; +} Token_TokenInstruction_Token_InitializeMultisig_Body; + +typedef struct Token_TokenInstruction_Token_Transfer_Body { + /** + * The amount of tokens to transfer. + */ + uint64_t amount; +} Token_TokenInstruction_Token_Transfer_Body; + +typedef struct Token_TokenInstruction_Token_Approve_Body { + /** + * The amount of tokens the delegate is approved for. + */ + uint64_t amount; +} Token_TokenInstruction_Token_Approve_Body; + +typedef struct Token_TokenInstruction_Token_MintTo_Body { + /** + * The amount of new tokens to mint. + */ + uint64_t amount; +} Token_TokenInstruction_Token_MintTo_Body; + +typedef struct Token_TokenInstruction_Token_Burn_Body { + /** + * The amount of tokens to burn. + */ + uint64_t amount; +} Token_TokenInstruction_Token_Burn_Body; + +typedef struct Token_TokenInstruction { + Token_TokenInstruction_Tag tag; + union { + Token_TokenInstruction_Token_InitializeMint_Body initialize_mint; + Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; + Token_TokenInstruction_Token_Transfer_Body transfer; + Token_TokenInstruction_Token_Approve_Body approve; + Token_TokenInstruction_Token_MintTo_Body mint_to; + Token_TokenInstruction_Token_Burn_Body burn; + }; +} Token_TokenInstruction; + +typedef uint8_t Token_Pubkey[32]; + +/** + * A C representation of Rust's `std::option::Option` + */ +typedef enum Token_COption_Pubkey_Tag { + /** + * No value + */ + Token_COption_Pubkey_None_Pubkey, + /** + * Some value `T` + */ + Token_COption_Pubkey_Some_Pubkey, +} Token_COption_Pubkey_Tag; + +typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { + Token_Pubkey _0; +} Token_COption_Pubkey_Token_Some_Body_Pubkey; + +typedef struct Token_COption_Pubkey { + Token_COption_Pubkey_Tag tag; + union { + Token_COption_Pubkey_Token_Some_Body_Pubkey some; + }; +} Token_COption_Pubkey; + +/** + * Mint data. + */ +typedef struct Token_Mint { + /** + * Optional owner, used to mint new tokens. The owner may only + * be provided during mint creation. If no owner is present then the mint + * has a fixed supply and no further tokens may be minted. + */ + Token_COption_Pubkey owner; + /** + * Number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; + /** + * Is `true` if this structure has been initialized + */ + bool is_initialized; +} Token_Mint; + +/** + * Account data. + */ +typedef struct Token_Account { + /** + * The mint associated with this account + */ + Token_Pubkey mint; + /** + * The owner of this account. + */ + Token_Pubkey owner; + /** + * The amount of tokens this account holds. + */ + uint64_t amount; + /** + * If `delegate` is `Some` then `delegated_amount` represents + * the amount authorized by the delegate + */ + Token_COption_Pubkey delegate; + /** + * Is `true` if this structure has been initialized + */ + bool is_initialized; + /** + * Is this a native token + */ + bool is_native; + /** + * The amount delegated + */ + uint64_t delegated_amount; +} Token_Account; + +/** + * Multisignature data. + */ +typedef struct Token_Multisig { + /** + * Number of signers required + */ + uint8_t m; + /** + * Number of valid signers + */ + uint8_t n; + /** + * Is `true` if this structure has been initialized + */ + bool is_initialized; + /** + * Signer public keys + */ + Token_Pubkey signers[Token_MAX_SIGNERS]; +} Token_Multisig; diff --git a/program/program-id.md b/program/program-id.md new file mode 100644 index 0000000..0e3c586 --- /dev/null +++ b/program/program-id.md @@ -0,0 +1 @@ +TokensVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs new file mode 100644 index 0000000..b5594ca --- /dev/null +++ b/program/src/entrypoint.rs @@ -0,0 +1,24 @@ +//! Program entrypoint + +#![cfg(feature = "program")] +#![cfg(not(feature = "no-entrypoint"))] + +use crate::{error::TokenError, processor::Processor}; +use solana_sdk::{ + account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, + program_error::PrintProgramError, pubkey::Pubkey, +}; + +entrypoint!(process_instruction); +fn process_instruction<'a>( + program_id: &Pubkey, + accounts: &'a [AccountInfo<'a>], + instruction_data: &[u8], +) -> ProgramResult { + if let Err(error) = Processor::process(program_id, accounts, instruction_data) { + // catch the error so we can print it + error.print::(); + return Err(error); + } + Ok(()) +} diff --git a/program/src/error.rs b/program/src/error.rs new file mode 100644 index 0000000..cc7da55 --- /dev/null +++ b/program/src/error.rs @@ -0,0 +1,71 @@ +//! Error types + +use num_derive::FromPrimitive; +use solana_sdk::{decode_error::DecodeError, program_error::ProgramError}; +use thiserror::Error; + +/// Errors that may be returned by the Token program. +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] +pub enum TokenError { + /// Insufficient funds for the operation requested. + #[error("Insufficient funds")] + InsufficientFunds, + /// Account not associated with this Mint. + #[error("Account not associated with this Mint")] + MintMismatch, + /// Owner does not match. + #[error("Owner does not match")] + OwnerMismatch, + /// This token's supply is fixed and new tokens cannot be minted. + #[error("Fixed supply")] + FixedSupply, + /// The account cannot be initialized because it is already being used. + #[error("AlreadyInUse")] + AlreadyInUse, + /// An owner is required if initial supply is zero. + #[error("An owner is required if supply is zero")] + OwnerRequiredIfNoInitialSupply, + /// Invalid number of provided signers. + #[error("Invalid number of provided signers")] + InvalidNumberOfProvidedSigners, + /// Invalid number of required signers. + #[error("Invalid number of required signers")] + InvalidNumberOfRequiredSigners, + /// State is uninitialized. + #[error("State is unititialized")] + UninitializedState, + /// Instruction does not support native tokens + #[error("Instruction does not support native tokens")] + NativeNotSupported, + /// Non-native account can only be closed if its balance is zero + #[error("Non-native account can only be closed if its balance is zero")] + NonNativeHasBalance, + /// Invalid instruction + #[error("Invalid instruction")] + InvalidInstruction, + /// State is invalid for requested operation. + #[error("State is invalid for requested operation")] + InvalidState, + /// Operation overflowed + #[error("Operation overflowed")] + Overflow, + /// Account does not support specified authority type. + #[error("Account does not support specified authority type")] + AuthorityTypeNotSupported, + /// This token mint cannot freeze accounts. + #[error("This token mint cannot freeze accounts")] + MintCannotFreeze, + /// Account is frozen; all account operations will fail + #[error("Account is frozen")] + AccountFrozen, +} +impl From for ProgramError { + fn from(e: TokenError) -> Self { + ProgramError::Custom(e as u32) + } +} +impl DecodeError for TokenError { + fn type_of() -> &'static str { + "TokenError" + } +} diff --git a/program/src/instruction.rs b/program/src/instruction.rs new file mode 100644 index 0000000..96acf76 --- /dev/null +++ b/program/src/instruction.rs @@ -0,0 +1,915 @@ +//! Instruction types + +use crate::{error::TokenError, option::COption}; +use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + pubkey::Pubkey, +}; +use std::mem::size_of; + +/// Minimum number of multisignature signers (min N) +pub const MIN_SIGNERS: usize = 1; +/// Maximum number of multisignature signers (max N) +pub const MAX_SIGNERS: usize = 11; + +/// Instructions supported by the token program. +#[repr(C)] +#[derive(Clone, Debug, PartialEq)] +pub enum TokenInstruction { + /// Initializes a new mint and optionally deposits all the newly minted tokens in an account. + /// + /// The `InitializeMint` instruction requires no signers and MUST be included within + /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The mint to initialize. + /// + InitializeMint { + /// Number of base 10 digits to the right of the decimal place. + decimals: u8, + /// The authority/multisignature to mint tokens. If present, further minting is supported. + mint_authority: COption, + /// The freeze authority/multisignature of the mint. + freeze_authority: COption, + }, + /// Initializes a new account to hold tokens. If this account is associated with the native mint + /// then the token balance of the initialized account will be equal to the amount of SOL in the account. + /// + /// The `InitializeAccount` instruction requires no signers and MUST be included within + /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// 1. `[]` The mint this account will be associated with. + /// 2. `[]` The new account's owner/multisignature. + InitializeAccount, + /// Initializes a multisignature account with N provided signers. + /// + /// Multisignature accounts can used in place of any single owner/delegate accounts in any + /// token instruction that require an owner/delegate to be present. The variant field represents the + /// number of signers (M) required to validate this multisignature account. + /// + /// The `InitializeMultisig` instruction requires no signers and MUST be included within + /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The multisignature account to initialize. + /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + InitializeMultisig { + /// The number of signers (M) required to validate this multisignature account. + m: u8, + }, + /// Transfers tokens from one account to another either directly or via a delegate. If this + /// account is associated with the native mint then equal amounts of SOL and Tokens will be + /// transferred to the destination account. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The source account. + /// 1. `[writable]` The destination account. + /// 2. '[signer]' The source account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The source account. + /// 1. `[writable]` The destination account. + /// 2. '[]' The source account's multisignature owner/delegate. + /// 3. ..3+M '[signer]' M signer accounts. + Transfer { + /// The amount of tokens to transfer. + amount: u64, + }, + /// Approves a delegate. A delegate is given the authority over + /// tokens on behalf of the source account's owner. + + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The source account. + /// 1. `[]` The delegate. + /// 2. `[signer]` The source account owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The source account. + /// 1. `[]` The delegate. + /// 2. '[]' The source account's multisignature owner. + /// 3. ..3+M '[signer]' M signer accounts + Approve { + /// The amount of tokens the delegate is approved for. + amount: u64, + }, + /// Revokes the delegate's authority. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The source account. + /// 1. `[signer]` The source account owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The source account. + /// 1. '[]' The source account's multisignature owner. + /// 2. ..2+M '[signer]' M signer accounts + Revoke, + /// Sets a new authority of a mint or account. + /// + /// Accounts expected by this instruction: + /// + /// * Single authority + /// 0. `[writable]` The mint or account to change the authority of. + /// 1. `[signer]` The current authority of the mint or account. + /// + /// * Multisignature authority + /// 0. `[writable]` The mint or account to change the authority of. + /// 1. `[]` The mint's or account's multisignature authority. + /// 3. ..3+M '[signer]' M signer accounts + SetAuthority { + /// The type of authority to update. + authority_type: AuthorityType, + /// The new authority + new_authority: COption, + }, + /// Mints new tokens to an account. The native mint does not support minting. + /// + /// Accounts expected by this instruction: + /// + /// * Single authority + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[signer]` The mint's minting authority. + /// + /// * Multisignature authority + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[]` The mint's multisignature mint-tokens authority. + /// 3. ..3+M '[signer]' M signer accounts. + MintTo { + /// The amount of new tokens to mint. + amount: u64, + }, + /// Burns tokens by removing them from an account. `Burn` does not support accounts + /// associated with the native mint, use `CloseAccount` instead. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. `[signer]` The account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. `[]` The account's multisignature owner/delegate. + /// 2. ..2+M '[signer]' M signer accounts. + Burn { + /// The amount of tokens to burn. + amount: u64, + }, + /// Close an account by transferring all its SOL to the destination account. + /// Non-native accounts may only be closed if its token amount is zero. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The account to close. + /// 1. '[writable]' The destination account. + /// 2. `[signer]` The account's owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The account to close. + /// 1. '[writable]' The destination account. + /// 2. `[]` The account's multisignature owner. + /// 3. ..3+M '[signer]' M signer accounts. + CloseAccount, + /// Freeze an Initialized account using the Mint's freeze_authority (if set). + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The account to freeze. + /// 1. '[]' The token mint. + /// 2. `[signer]` The mint freeze authority. + /// + /// * Multisignature owner + /// 0. `[writable]` The account to freeze. + /// 1. '[]' The token mint. + /// 2. `[]` The mint's multisignature freeze authority. + /// 3. ..3+M '[signer]' M signer accounts. + FreezeAccount, + /// Thaw a Frozen account using the Mint's freeze_authority (if set). + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The account to freeze. + /// 1. '[]' The token mint. + /// 2. `[signer]` The mint freeze authority. + /// + /// * Multisignature owner + /// 0. `[writable]` The account to freeze. + /// 1. '[]' The token mint. + /// 2. `[]` The mint's multisignature freeze authority. + /// 3. ..3+M '[signer]' M signer accounts. + ThawAccount, +} +impl TokenInstruction { + /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). + pub fn unpack(input: &[u8]) -> Result { + if input.len() < size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + Ok(match input[0] { + 0 => { + if input.len() < size_of::() + size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + let mut input_len = 0; + input_len += size_of::(); + + let decimals = unsafe { *(&input[input_len] as *const u8) }; + input_len += size_of::(); + + let mint_authority = COption::unpack_or( + input, + &mut input_len, + Into::::into(TokenError::InvalidInstruction), + )?; + let freeze_authority = COption::unpack_or( + input, + &mut input_len, + Into::::into(TokenError::InvalidInstruction), + )?; + + Self::InitializeMint { + mint_authority, + freeze_authority, + decimals, + } + } + 1 => Self::InitializeAccount, + 2 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let m = unsafe { *(&input[1] as *const u8) }; + Self::InitializeMultisig { m } + } + 3 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + Self::Transfer { amount } + } + 4 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + Self::Approve { amount } + } + 5 => Self::Revoke, + 6 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + let mut input_len = 0; + input_len += size_of::(); + let authority_type = AuthorityType::from(input[1])?; + input_len += size_of::(); + + let new_authority = COption::unpack_or( + input, + &mut input_len, + Into::::into(TokenError::InvalidInstruction), + )?; + + Self::SetAuthority { + authority_type, + new_authority, + } + } + 7 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + Self::MintTo { amount } + } + 8 => { + if input.len() < size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; + Self::Burn { amount } + } + 9 => Self::CloseAccount, + 10 => Self::FreezeAccount, + 11 => Self::ThawAccount, + _ => return Err(TokenError::InvalidInstruction.into()), + }) + } + + /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. + pub fn pack(&self) -> Result, ProgramError> { + let mut output = vec![0u8; size_of::()]; + let mut output_len = 0; + match self { + Self::InitializeMint { + mint_authority, + freeze_authority, + decimals, + } => { + output[output_len] = 0; + output_len += size_of::(); + + let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; + *value = *decimals; + output_len += size_of::(); + + mint_authority.pack(&mut output, &mut output_len); + freeze_authority.pack(&mut output, &mut output_len); + } + Self::InitializeAccount => { + output[output_len] = 1; + output_len += size_of::(); + } + Self::InitializeMultisig { m } => { + output[output_len] = 2; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u8) }; + *value = *m; + output_len += size_of::(); + } + Self::Transfer { amount } => { + output[output_len] = 3; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; + *value = *amount; + output_len += size_of::(); + } + Self::Approve { amount } => { + output[output_len] = 4; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; + *value = *amount; + output_len += size_of::(); + } + Self::Revoke => { + output[output_len] = 5; + output_len += size_of::(); + } + Self::SetAuthority { + authority_type, + new_authority, + } => { + output[output_len] = 6; + output_len += size_of::(); + + output[output_len] = authority_type.into(); + output_len += size_of::(); + + new_authority.pack(&mut output, &mut output_len); + } + Self::MintTo { amount } => { + output[output_len] = 7; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; + *value = *amount; + output_len += size_of::(); + } + Self::Burn { amount } => { + output[output_len] = 8; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; + *value = *amount; + output_len += size_of::(); + } + Self::CloseAccount => { + output[output_len] = 9; + output_len += size_of::(); + } + Self::FreezeAccount => { + output[output_len] = 10; + output_len += size_of::(); + } + Self::ThawAccount => { + output[output_len] = 11; + output_len += size_of::(); + } + } + + output.truncate(output_len); + Ok(output) + } +} + +/// Specifies the authority type for SetAuthority instructions +#[repr(u8)] +#[derive(Clone, Debug, PartialEq)] +pub enum AuthorityType { + /// Authority to mint new tokens + MintTokens, + /// Authority to freeze any account associated with the Mint + FreezeAccount, + /// Holder of a given token account + AccountHolder, + /// Authority to close a token account + CloseAccount, +} + +impl AuthorityType { + fn into(&self) -> u8 { + match self { + AuthorityType::MintTokens => 0, + AuthorityType::FreezeAccount => 1, + AuthorityType::AccountHolder => 2, + AuthorityType::CloseAccount => 3, + } + } + + fn from(index: u8) -> Result { + match index { + 0 => Ok(AuthorityType::MintTokens), + 1 => Ok(AuthorityType::FreezeAccount), + 2 => Ok(AuthorityType::AccountHolder), + 3 => Ok(AuthorityType::CloseAccount), + _ => Err(TokenError::InvalidInstruction.into()), + } + } +} + +/// Creates a 'InitializeMint' instruction. +pub fn initialize_mint( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, + mint_authority_pubkey: &Pubkey, + freeze_authority_pubkey: Option<&Pubkey>, + decimals: u8, +) -> Result { + let mint_authority = COption::Some(*mint_authority_pubkey); + let freeze_authority = freeze_authority_pubkey.cloned().into(); + let data = TokenInstruction::InitializeMint { + mint_authority, + freeze_authority, + decimals, + } + .pack()?; + + let accounts = vec![AccountMeta::new(*mint_pubkey, false)]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `InitializeAccount` instruction. +pub fn initialize_account( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + owner_pubkey: &Pubkey, +) -> Result { + let data = TokenInstruction::InitializeAccount.pack()?; + + let accounts = vec![ + AccountMeta::new(*account_pubkey, false), + AccountMeta::new_readonly(*mint_pubkey, false), + AccountMeta::new_readonly(*owner_pubkey, false), + ]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `InitializeMultisig` instruction. +pub fn initialize_multisig( + token_program_id: &Pubkey, + multisig_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + m: u8, +) -> Result { + if !is_valid_signer_index(m as usize) + || !is_valid_signer_index(signer_pubkeys.len()) + || m as usize > signer_pubkeys.len() + { + return Err(ProgramError::MissingRequiredSignature); + } + let data = TokenInstruction::InitializeMultisig { m }.pack()?; + + let mut accounts = Vec::with_capacity(1 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*multisig_pubkey, false)); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `Transfer` instruction. +pub fn transfer( + token_program_id: &Pubkey, + source_pubkey: &Pubkey, + destination_pubkey: &Pubkey, + authority_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, +) -> Result { + let data = TokenInstruction::Transfer { amount }.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*source_pubkey, false)); + accounts.push(AccountMeta::new(*destination_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *authority_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates an `Approve` instruction. +pub fn approve( + token_program_id: &Pubkey, + source_pubkey: &Pubkey, + delegate_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, +) -> Result { + let data = TokenInstruction::Approve { amount }.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*source_pubkey, false)); + accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `Revoke` instruction. +pub fn revoke( + token_program_id: &Pubkey, + source_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], +) -> Result { + let data = TokenInstruction::Revoke.pack()?; + + let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); + accounts.push(AccountMeta::new_readonly(*source_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `SetAuthority` instruction. +pub fn set_authority( + token_program_id: &Pubkey, + owned_pubkey: &Pubkey, + new_authority_pubkey: Option<&Pubkey>, + authority_type: AuthorityType, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], +) -> Result { + let new_authority = new_authority_pubkey.cloned().into(); + let data = TokenInstruction::SetAuthority { + authority_type, + new_authority, + } + .pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*owned_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `MintTo` instruction. +pub fn mint_to( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, + account_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, +) -> Result { + let data = TokenInstruction::MintTo { amount }.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*mint_pubkey, false)); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `Burn` instruction. +pub fn burn( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + authority_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, +) -> Result { + let data = TokenInstruction::Burn { amount }.pack()?; + + let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *authority_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `CloseAccount` instruction. +pub fn close_account( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + destination_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], +) -> Result { + let data = TokenInstruction::CloseAccount.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new(*destination_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `FreezeAccount` instruction. +pub fn freeze_account( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], +) -> Result { + let data = TokenInstruction::FreezeAccount.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `ThawAccount` instruction. +pub fn thaw_account( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], +) -> Result { + let data = TokenInstruction::ThawAccount.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS +pub fn is_valid_signer_index(index: usize) -> bool { + !(index < MIN_SIGNERS || index > MAX_SIGNERS) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_instruction_packing() { + let check = TokenInstruction::InitializeMint { + decimals: 2, + mint_authority: COption::None, + freeze_authority: COption::None, + }; + let packed = check.pack().unwrap(); + let expect = Vec::from([0u8, 2, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeMint { + decimals: 2, + mint_authority: COption::Some(Pubkey::new(&[2u8; 32])), + freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), + }; + let packed = check.pack().unwrap(); + let mut expect = vec![0u8, 2]; + expect.extend_from_slice(&[1]); + expect.extend_from_slice(&[2u8; 32]); + expect.extend_from_slice(&[1]); + expect.extend_from_slice(&[3u8; 32]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeAccount; + let packed = check.pack().unwrap(); + let expect = Vec::from([1u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeMultisig { m: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([2u8, 1]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Transfer { amount: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Approve { amount: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Revoke; + let packed = check.pack().unwrap(); + let expect = Vec::from([5u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::SetAuthority { + authority_type: AuthorityType::FreezeAccount, + new_authority: COption::Some(Pubkey::new(&[4u8; 32])), + }; + let packed = check.pack().unwrap(); + let mut expect = Vec::from([6u8, 1]); + expect.extend_from_slice(&[1]); + expect.extend_from_slice(&[4u8; 32]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::MintTo { amount: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Burn { amount: 1 }; + let packed = check.pack().unwrap(); + let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::CloseAccount; + let packed = check.pack().unwrap(); + let expect = Vec::from([9u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::FreezeAccount; + let packed = check.pack().unwrap(); + let expect = Vec::from([10u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::ThawAccount; + let packed = check.pack().unwrap(); + let expect = Vec::from([11u8]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + } +} diff --git a/program/src/lib.rs b/program/src/lib.rs new file mode 100644 index 0000000..c6096a5 --- /dev/null +++ b/program/src/lib.rs @@ -0,0 +1,28 @@ +#![deny(missing_docs)] + +//! An ERC20-like Token program for the Solana blockchain + +pub mod entrypoint; +pub mod error; +pub mod instruction; +pub mod native_mint; +pub mod option; +pub mod processor; +pub mod state; + +// Export current solana-sdk types for downstream users who may also be building with a different +// solana-sdk version +pub use solana_sdk; + +/// Convert the UI representation of a token amount (using the decimals field defined in its mint) +/// to the raw amount +pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { + (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 +} + +/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { + amount as f64 / 10_usize.pow(decimals as u32) as f64 +} + +solana_sdk::declare_id!("TokensVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"); diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs new file mode 100644 index 0000000..e502128 --- /dev/null +++ b/program/src/native_mint.rs @@ -0,0 +1,24 @@ +//! The Mint that represents the native token + +/// There are 10^9 lamports in one SOL +pub const DECIMALS: u8 = 9; + +// The Mint for native SOL Token accounts +solana_sdk::declare_id!("So12111111111111111111111111111111111111111"); + +#[cfg(test)] +mod tests { + use super::*; + use solana_sdk::native_token::*; + + #[test] + fn test_decimals() { + assert!( + lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS).abs() < f64::EPSILON + ); + assert_eq!( + sol_to_lamports(42.), + crate::ui_amount_to_amount(42., DECIMALS) + ); + } +} diff --git a/program/src/option.rs b/program/src/option.rs new file mode 100644 index 0000000..9e6f16d --- /dev/null +++ b/program/src/option.rs @@ -0,0 +1,1112 @@ +//! A C representation of Rust's `std::option::Option` used accross the FFI +//! boundary for Solana program interfaces +//! +//! This implementation mostly matches `std::option` except iterators since the iteration +//! trait requires returning `std::option::Option` + +use std::pin::Pin; +use std::{ + convert, hint, mem, + ops::{Deref, DerefMut}, +}; + +/// A C representation of Rust's `std::option::Option` +#[repr(C)] +#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +pub enum COption { + /// No value + None, + /// Some value `T` + Some(T), +} + +///////////////////////////////////////////////////////////////////////////// +// Type implementation +///////////////////////////////////////////////////////////////////////////// + +impl COption { + ///////////////////////////////////////////////////////////////////////// + // Querying the contained values + ///////////////////////////////////////////////////////////////////////// + + /// Returns `true` if the option is a [`COption::Some`] value. + /// + /// # Examples + /// + /// ```ignore + /// let x: COption = COption::Some(2); + /// assert_eq!(x.is_some(), true); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.is_some(), false); + /// ``` + /// + /// [`COption::Some`]: #variant.COption::Some + #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] + #[inline] + pub fn is_some(&self) -> bool { + match *self { + COption::Some(_) => true, + COption::None => false, + } + } + + /// Returns `true` if the option is a [`COption::None`] value. + /// + /// # Examples + /// + /// ```ignore + /// let x: COption = COption::Some(2); + /// assert_eq!(x.is_none(), false); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.is_none(), true); + /// ``` + /// + /// [`COption::None`]: #variant.COption::None + #[must_use = "if you intended to assert that this doesn't have a value, consider \ + `.and_then(|| panic!(\"`COption` had a value when expected `COption::None`\"))` instead"] + #[inline] + pub fn is_none(&self) -> bool { + !self.is_some() + } + + /// Returns `true` if the option is a [`COption::Some`] value containing the given value. + /// + /// # Examples + /// + /// ```ignore + /// #![feature(option_result_contains)] + /// + /// let x: COption = COption::Some(2); + /// assert_eq!(x.contains(&2), true); + /// + /// let x: COption = COption::Some(3); + /// assert_eq!(x.contains(&2), false); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.contains(&2), false); + /// ``` + #[must_use] + #[inline] + pub fn contains(&self, x: &U) -> bool + where + U: PartialEq, + { + match self { + COption::Some(y) => x == y, + COption::None => false, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Adapter for working with references + ///////////////////////////////////////////////////////////////////////// + + /// Converts from `&COption` to `COption<&T>`. + /// + /// # Examples + /// + /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, preserving the original. + /// The [`map`] method takes the `self` argument by value, consuming the original, + /// so this technique uses `as_ref` to first take an `COption` to a reference + /// to the value inside the original. + /// + /// [`map`]: enum.COption.html#method.map + /// [`String`]: ../../std/string/struct.String.html + /// [`usize`]: ../../std/primitive.usize.html + /// + /// ```ignore + /// let text: COption = COption::Some("Hello, world!".to_string()); + /// // First, cast `COption` to `COption<&String>` with `as_ref`, + /// // then consume *that* with `map`, leaving `text` on the stack. + /// let text_length: COption = text.as_ref().map(|s| s.len()); + /// println!("still can print text: {:?}", text); + /// ``` + #[inline] + pub fn as_ref(&self) -> COption<&T> { + match *self { + COption::Some(ref x) => COption::Some(x), + COption::None => COption::None, + } + } + + /// Converts from `&mut COption` to `COption<&mut T>`. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::Some(2); + /// match x.as_mut() { + /// COption::Some(v) => *v = 42, + /// COption::None => {}, + /// } + /// assert_eq!(x, COption::Some(42)); + /// ``` + #[inline] + pub fn as_mut(&mut self) -> COption<&mut T> { + match *self { + COption::Some(ref mut x) => COption::Some(x), + COption::None => COption::None, + } + } + + /// Converts from [`Pin`]`<&COption>` to `COption<`[`Pin`]`<&T>>`. + /// + /// [`Pin`]: ../pin/struct.Pin.html + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn as_pin_ref(self: Pin<&Self>) -> COption> { + unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } + } + + /// Converts from [`Pin`]`<&mut COption>` to `COption<`[`Pin`]`<&mut T>>`. + /// + /// [`Pin`]: ../pin/struct.Pin.html + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn as_pin_mut(self: Pin<&mut Self>) -> COption> { + unsafe { + Pin::get_unchecked_mut(self) + .as_mut() + .map(|x| Pin::new_unchecked(x)) + } + } + + ///////////////////////////////////////////////////////////////////////// + // Getting to contained values + ///////////////////////////////////////////////////////////////////////// + + /// Unwraps an option, yielding the content of a [`COption::Some`]. + /// + /// # Panics + /// + /// Panics if the value is a [`COption::None`] with a custom panic message provided by + /// `msg`. + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("value"); + /// assert_eq!(x.expect("the world is ending"), "value"); + /// ``` + /// + /// ```ignore{.should_panic} + /// let x: COption<&str> = COption::None; + /// x.expect("the world is ending"); // panics with `the world is ending` + /// ``` + #[inline] + pub fn expect(self, msg: &str) -> T { + match self { + COption::Some(val) => val, + COption::None => expect_failed(msg), + } + } + + /// Moves the value `v` out of the `COption` if it is [`COption::Some(v)`]. + /// + /// In general, because this function may panic, its use is discouraged. + /// Instead, prefer to use pattern matching and handle the [`COption::None`] + /// case explicitly. + /// + /// # Panics + /// + /// Panics if the self value equals [`COption::None`]. + /// + /// [`COption::Some(v)`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("air"); + /// assert_eq!(x.unwrap(), "air"); + /// ``` + /// + /// ```ignore{.should_panic} + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.unwrap(), "air"); // fails + /// ``` + #[inline] + pub fn unwrap(self) -> T { + match self { + COption::Some(val) => val, + COption::None => panic!("called `COption::unwrap()` on a `COption::None` value"), + } + } + + /// Returns the contained value or a default. + /// + /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use [`unwrap_or_else`], + /// which is lazily evaluated. + /// + /// [`unwrap_or_else`]: #method.unwrap_or_else + /// + /// # Examples + /// + /// ```ignore + /// assert_eq!(COption::Some("car").unwrap_or("bike"), "car"); + /// assert_eq!(COption::None.unwrap_or("bike"), "bike"); + /// ``` + #[inline] + pub fn unwrap_or(self, def: T) -> T { + match self { + COption::Some(x) => x, + COption::None => def, + } + } + + /// Returns the contained value or computes it from a closure. + /// + /// # Examples + /// + /// ```ignore + /// let k = 10; + /// assert_eq!(COption::Some(4).unwrap_or_else(|| 2 * k), 4); + /// assert_eq!(COption::None.unwrap_or_else(|| 2 * k), 20); + /// ``` + #[inline] + pub fn unwrap_or_else T>(self, f: F) -> T { + match self { + COption::Some(x) => x, + COption::None => f(), + } + } + + ///////////////////////////////////////////////////////////////////////// + // Transforming contained values + ///////////////////////////////////////////////////////////////////////// + + /// Maps an `COption` to `COption` by applying a function to a contained value. + /// + /// # Examples + /// + /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, consuming the original: + /// + /// [`String`]: ../../std/string/struct.String.html + /// [`usize`]: ../../std/primitive.usize.html + /// + /// ```ignore + /// let maybe_some_string = COption::Some(String::from("Hello, World!")); + /// // `COption::map` takes self *by value*, consuming `maybe_some_string` + /// let maybe_some_len = maybe_some_string.map(|s| s.len()); + /// + /// assert_eq!(maybe_some_len, COption::Some(13)); + /// ``` + #[inline] + pub fn map U>(self, f: F) -> COption { + match self { + COption::Some(x) => COption::Some(f(x)), + COption::None => COption::None, + } + } + + /// Applies a function to the contained value (if any), + /// or returns the provided default (if not). + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.map_or(42, |v| v.len()), 3); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.map_or(42, |v| v.len()), 42); + /// ``` + #[inline] + pub fn map_or U>(self, default: U, f: F) -> U { + match self { + COption::Some(t) => f(t), + COption::None => default, + } + } + + /// Applies a function to the contained value (if any), + /// or computes a default (if not). + /// + /// # Examples + /// + /// ```ignore + /// let k = 21; + /// + /// let x = COption::Some("foo"); + /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42); + /// ``` + #[inline] + pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { + match self { + COption::Some(t) => f(t), + COption::None => default(), + } + } + + /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to + /// [`Ok(v)`] and [`COption::None`] to [`Err(err)`]. + /// + /// Arguments passed to `ok_or` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`ok_or_else`], which is + /// lazily evaluated. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Err(err)`]: ../../std/result/enum.Result.html#variant.Err + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(v)`]: #variant.COption::Some + /// [`ok_or_else`]: #method.ok_or_else + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.ok_or(0), Ok("foo")); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.ok_or(0), Err(0)); + /// ``` + #[inline] + pub fn ok_or(self, err: E) -> Result { + match self { + COption::Some(v) => Ok(v), + COption::None => Err(err), + } + } + + /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to + /// [`Ok(v)`] and [`COption::None`] to [`Err(err())`]. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Err(err())`]: ../../std/result/enum.Result.html#variant.Err + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(v)`]: #variant.COption::Some + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.ok_or_else(|| 0), Ok("foo")); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.ok_or_else(|| 0), Err(0)); + /// ``` + #[inline] + pub fn ok_or_else E>(self, err: F) -> Result { + match self { + COption::Some(v) => Ok(v), + COption::None => Err(err()), + } + } + + ///////////////////////////////////////////////////////////////////////// + // Boolean operations on the values, eager and lazy + ///////////////////////////////////////////////////////////////////////// + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise returns `optb`. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y: COption<&str> = COption::None; + /// assert_eq!(x.and(y), COption::None); + /// + /// let x: COption = COption::None; + /// let y = COption::Some("foo"); + /// assert_eq!(x.and(y), COption::None); + /// + /// let x = COption::Some(2); + /// let y = COption::Some("foo"); + /// assert_eq!(x.and(y), COption::Some("foo")); + /// + /// let x: COption = COption::None; + /// let y: COption<&str> = COption::None; + /// assert_eq!(x.and(y), COption::None); + /// ``` + #[inline] + pub fn and(self, optb: COption) -> COption { + match self { + COption::Some(_) => optb, + COption::None => COption::None, + } + } + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `f` with the + /// wrapped value and returns the result. + /// + /// COption::Some languages call this operation flatmap. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// fn sq(x: u32) -> COption { COption::Some(x * x) } + /// fn nope(_: u32) -> COption { COption::None } + /// + /// assert_eq!(COption::Some(2).and_then(sq).and_then(sq), COption::Some(16)); + /// assert_eq!(COption::Some(2).and_then(sq).and_then(nope), COption::None); + /// assert_eq!(COption::Some(2).and_then(nope).and_then(sq), COption::None); + /// assert_eq!(COption::None.and_then(sq).and_then(sq), COption::None); + /// ``` + #[inline] + pub fn and_then COption>(self, f: F) -> COption { + match self { + COption::Some(x) => f(x), + COption::None => COption::None, + } + } + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `predicate` + /// with the wrapped value and returns: + /// + /// - [`COption::Some(t)`] if `predicate` returns `true` (where `t` is the wrapped + /// value), and + /// - [`COption::None`] if `predicate` returns `false`. + /// + /// This function works similar to [`Iterator::filter()`]. You can imagine + /// the `COption` being an iterator over one or zero elements. `filter()` + /// lets you decide which elements to keep. + /// + /// # Examples + /// + /// ```ignore + /// fn is_even(n: &i32) -> bool { + /// n % 2 == 0 + /// } + /// + /// assert_eq!(COption::None.filter(is_even), COption::None); + /// assert_eq!(COption::Some(3).filter(is_even), COption::None); + /// assert_eq!(COption::Some(4).filter(is_even), COption::Some(4)); + /// ``` + /// + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(t)`]: #variant.COption::Some + /// [`Iterator::filter()`]: ../../std/iter/trait.Iterator.html#method.filter + #[inline] + pub fn filter bool>(self, predicate: P) -> Self { + if let COption::Some(x) = self { + if predicate(&x) { + return COption::Some(x); + } + } + COption::None + } + + /// Returns the option if it contains a value, otherwise returns `optb`. + /// + /// Arguments passed to `or` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`or_else`], which is + /// lazily evaluated. + /// + /// [`or_else`]: #method.or_else + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y = COption::None; + /// assert_eq!(x.or(y), COption::Some(2)); + /// + /// let x = COption::None; + /// let y = COption::Some(100); + /// assert_eq!(x.or(y), COption::Some(100)); + /// + /// let x = COption::Some(2); + /// let y = COption::Some(100); + /// assert_eq!(x.or(y), COption::Some(2)); + /// + /// let x: COption = COption::None; + /// let y = COption::None; + /// assert_eq!(x.or(y), COption::None); + /// ``` + #[inline] + pub fn or(self, optb: COption) -> COption { + match self { + COption::Some(_) => self, + COption::None => optb, + } + } + + /// Returns the option if it contains a value, otherwise calls `f` and + /// returns the result. + /// + /// # Examples + /// + /// ```ignore + /// fn nobody() -> COption<&'static str> { COption::None } + /// fn vikings() -> COption<&'static str> { COption::Some("vikings") } + /// + /// assert_eq!(COption::Some("barbarians").or_else(vikings), COption::Some("barbarians")); + /// assert_eq!(COption::None.or_else(vikings), COption::Some("vikings")); + /// assert_eq!(COption::None.or_else(nobody), COption::None); + /// ``` + #[inline] + pub fn or_else COption>(self, f: F) -> COption { + match self { + COption::Some(_) => self, + COption::None => f(), + } + } + + /// Returns [`COption::Some`] if exactly one of `self`, `optb` is [`COption::Some`], otherwise returns [`COption::None`]. + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y: COption = COption::None; + /// assert_eq!(x.xor(y), COption::Some(2)); + /// + /// let x: COption = COption::None; + /// let y = COption::Some(2); + /// assert_eq!(x.xor(y), COption::Some(2)); + /// + /// let x = COption::Some(2); + /// let y = COption::Some(2); + /// assert_eq!(x.xor(y), COption::None); + /// + /// let x: COption = COption::None; + /// let y: COption = COption::None; + /// assert_eq!(x.xor(y), COption::None); + /// ``` + #[inline] + pub fn xor(self, optb: COption) -> COption { + match (self, optb) { + (COption::Some(a), COption::None) => COption::Some(a), + (COption::None, COption::Some(b)) => COption::Some(b), + _ => COption::None, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Entry-like operations to insert if COption::None and return a reference + ///////////////////////////////////////////////////////////////////////// + + /// Inserts `v` into the option if it is [`COption::None`], then + /// returns a mutable reference to the contained value. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::None; + /// + /// { + /// let y: &mut u32 = x.get_or_insert(5); + /// assert_eq!(y, &5); + /// + /// *y = 7; + /// } + /// + /// assert_eq!(x, COption::Some(7)); + /// ``` + #[inline] + pub fn get_or_insert(&mut self, v: T) -> &mut T { + self.get_or_insert_with(|| v) + } + + /// Inserts a value computed from `f` into the option if it is [`COption::None`], then + /// returns a mutable reference to the contained value. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::None; + /// + /// { + /// let y: &mut u32 = x.get_or_insert_with(|| 5); + /// assert_eq!(y, &5); + /// + /// *y = 7; + /// } + /// + /// assert_eq!(x, COption::Some(7)); + /// ``` + #[inline] + pub fn get_or_insert_with T>(&mut self, f: F) -> &mut T { + if let COption::None = *self { + *self = COption::Some(f()) + } + + match *self { + COption::Some(ref mut v) => v, + COption::None => unsafe { hint::unreachable_unchecked() }, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Misc + ///////////////////////////////////////////////////////////////////////// + + /// Replaces the actual value in the option by the value given in parameter, + /// returning the old value if present, + /// leaving a [`COption::Some`] in its place without deinitializing either one. + /// + /// [`COption::Some`]: #variant.COption::Some + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::Some(2); + /// let old = x.replace(5); + /// assert_eq!(x, COption::Some(5)); + /// assert_eq!(old, COption::Some(2)); + /// + /// let mut x = COption::None; + /// let old = x.replace(3); + /// assert_eq!(x, COption::Some(3)); + /// assert_eq!(old, COption::None); + /// ``` + #[inline] + pub fn replace(&mut self, value: T) -> COption { + mem::replace(self, COption::Some(value)) + } + + ///////////////////////////////////////////////////////////////////////// + // SPL Token-Specific Methods + ///////////////////////////////////////////////////////////////////////// + + /// Packs a COption into a mutable slice as compactly as possible + #[inline] + pub fn pack(&self, output: &mut [u8], cursor: &mut usize) + where + T: Copy, + { + match self { + COption::Some(some_value) => { + output[*cursor] = 1; + *cursor += mem::size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[*cursor] as *mut u8 as *mut T) }; + *value = *some_value; + *cursor += mem::size_of::(); + } + COption::None => { + output[*cursor] = 0; + *cursor += mem::size_of::(); + } + } + } + + /// Unpacks a COption from a compact slice + #[inline] + pub fn unpack_or(input: &[u8], cursor: &mut usize, error: E) -> Result, E> + where + T: Copy, + { + match input[*cursor] { + 0 => { + *cursor += mem::size_of::(); + Ok(COption::None) + } + 1 => { + *cursor += mem::size_of::(); + #[allow(clippy::cast_ptr_alignment)] + let result = unsafe { *(&input[*cursor] as *const u8 as *const T) }; + *cursor += mem::size_of::(); + Ok(COption::Some(result)) + } + _ => Err(error), + } + } +} + +impl COption<&T> { + /// Maps an `COption<&T>` to an `COption` by copying the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let x = 12; + /// let opt_x = COption::Some(&x); + /// assert_eq!(opt_x, COption::Some(&12)); + /// let copied = opt_x.copied(); + /// assert_eq!(copied, COption::Some(12)); + /// ``` + pub fn copied(self) -> COption { + self.map(|&t| t) + } +} + +impl COption<&mut T> { + /// Maps an `COption<&mut T>` to an `COption` by copying the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = 12; + /// let opt_x = COption::Some(&mut x); + /// assert_eq!(opt_x, COption::Some(&mut 12)); + /// let copied = opt_x.copied(); + /// assert_eq!(copied, COption::Some(12)); + /// ``` + pub fn copied(self) -> COption { + self.map(|&mut t| t) + } +} + +impl COption<&T> { + /// Maps an `COption<&T>` to an `COption` by cloning the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let x = 12; + /// let opt_x = COption::Some(&x); + /// assert_eq!(opt_x, COption::Some(&12)); + /// let cloned = opt_x.cloned(); + /// assert_eq!(cloned, COption::Some(12)); + /// ``` + pub fn cloned(self) -> COption { + self.map(|t| t.clone()) + } +} + +impl COption<&mut T> { + /// Maps an `COption<&mut T>` to an `COption` by cloning the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = 12; + /// let opt_x = COption::Some(&mut x); + /// assert_eq!(opt_x, COption::Some(&mut 12)); + /// let cloned = opt_x.cloned(); + /// assert_eq!(cloned, COption::Some(12)); + /// ``` + pub fn cloned(self) -> COption { + self.map(|t| t.clone()) + } +} + +impl COption { + /// Returns the contained value or a default + /// + /// Consumes the `self` argument then, if [`COption::Some`], returns the contained + /// value, otherwise if [`COption::None`], returns the [default value] for that + /// type. + /// + /// # Examples + /// + /// Converts a string to an integer, turning poorly-formed strings + /// into 0 (the default value for integers). [`parse`] converts + /// a string to any other type that implements [`FromStr`], returning + /// [`COption::None`] on error. + /// + /// ```ignore + /// let good_year_from_input = "1909"; + /// let bad_year_from_input = "190blarg"; + /// let good_year = good_year_from_input.parse().ok().unwrap_or_default(); + /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default(); + /// + /// assert_eq!(1909, good_year); + /// assert_eq!(0, bad_year); + /// ``` + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// [default value]: ../default/trait.Default.html#tymethod.default + /// [`parse`]: ../../std/primitive.str.html#method.parse + /// [`FromStr`]: ../../std/str/trait.FromStr.html + #[inline] + pub fn unwrap_or_default(self) -> T { + match self { + COption::Some(x) => x, + COption::None => Default::default(), + } + } +} + +impl COption { + /// Converts from `COption` (or `&COption`) to `COption<&T::Target>`. + /// + /// Leaves the original COption in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via [`Deref`]. + /// + /// [`Deref`]: ../../std/ops/trait.Deref.html + /// + /// # Examples + /// + /// ```ignore + /// #![feature(inner_deref)] + /// + /// let x: COption = COption::Some("hey".to_owned()); + /// assert_eq!(x.as_deref(), COption::Some("hey")); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.as_deref(), COption::None); + /// ``` + pub fn as_deref(&self) -> COption<&T::Target> { + self.as_ref().map(|t| t.deref()) + } +} + +impl COption { + /// Converts from `COption` (or `&mut COption`) to `COption<&mut T::Target>`. + /// + /// Leaves the original `COption` in-place, creating a new one containing a mutable reference to + /// the inner type's `Deref::Target` type. + /// + /// # Examples + /// + /// ```ignore + /// #![feature(inner_deref)] + /// + /// let mut x: COption = COption::Some("hey".to_owned()); + /// assert_eq!(x.as_deref_mut().map(|x| { + /// x.make_ascii_uppercase(); + /// x + /// }), COption::Some("HEY".to_owned().as_mut_str())); + /// ``` + pub fn as_deref_mut(&mut self) -> COption<&mut T::Target> { + self.as_mut().map(|t| t.deref_mut()) + } +} + +impl COption> { + /// Transposes an `COption` of a [`Result`] into a [`Result`] of an `COption`. + /// + /// [`COption::None`] will be mapped to [`Ok`]`(`[`COption::None`]`)`. + /// [`COption::Some`]`(`[`Ok`]`(_))` and [`COption::Some`]`(`[`Err`]`(_))` will be mapped to + /// [`Ok`]`(`[`COption::Some`]`(_))` and [`Err`]`(_)`. + /// + /// [`COption::None`]: #variant.COption::None + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`COption::Some`]: #variant.COption::Some + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ```ignore + /// #[derive(Debug, Eq, PartialEq)] + /// struct COption::SomeErr; + /// + /// let x: Result, COption::SomeErr> = Ok(COption::Some(5)); + /// let y: COption> = COption::Some(Ok(5)); + /// assert_eq!(x, y.transpose()); + /// ``` + #[inline] + pub fn transpose(self) -> Result, E> { + match self { + COption::Some(Ok(x)) => Ok(COption::Some(x)), + COption::Some(Err(e)) => Err(e), + COption::None => Ok(COption::None), + } + } +} + +// This is a separate function to reduce the code size of .expect() itself. +#[inline(never)] +#[cold] +fn expect_failed(msg: &str) -> ! { + panic!("{}", msg) +} + +// // This is a separate function to reduce the code size of .expect_none() itself. +// #[inline(never)] +// #[cold] +// fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! { +// panic!("{}: {:?}", msg, value) +// } + +///////////////////////////////////////////////////////////////////////////// +// Trait implementations +///////////////////////////////////////////////////////////////////////////// + +impl Clone for COption { + #[inline] + fn clone(&self) -> Self { + match self { + COption::Some(x) => COption::Some(x.clone()), + COption::None => COption::None, + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + match (self, source) { + (COption::Some(to), COption::Some(from)) => to.clone_from(from), + (to, from) => *to = from.clone(), + } + } +} + +impl Default for COption { + /// Returns [`COption::None`][COption::COption::None]. + /// + /// # Examples + /// + /// ```ignore + /// let opt: COption = COption::default(); + /// assert!(opt.is_none()); + /// ``` + #[inline] + fn default() -> COption { + COption::None + } +} + +impl From for COption { + fn from(val: T) -> COption { + COption::Some(val) + } +} + +impl<'a, T> From<&'a COption> for COption<&'a T> { + fn from(o: &'a COption) -> COption<&'a T> { + o.as_ref() + } +} + +impl<'a, T> From<&'a mut COption> for COption<&'a mut T> { + fn from(o: &'a mut COption) -> COption<&'a mut T> { + o.as_mut() + } +} + +impl COption> { + /// Converts from `COption>` to `COption` + /// + /// # Examples + /// Basic usage: + /// ```ignore + /// #![feature(option_flattening)] + /// let x: COption> = COption::Some(COption::Some(6)); + /// assert_eq!(COption::Some(6), x.flatten()); + /// + /// let x: COption> = COption::Some(COption::None); + /// assert_eq!(COption::None, x.flatten()); + /// + /// let x: COption> = COption::None; + /// assert_eq!(COption::None, x.flatten()); + /// ``` + /// Flattening once only removes one level of nesting: + /// ```ignore + /// #![feature(option_flattening)] + /// let x: COption>> = COption::Some(COption::Some(COption::Some(6))); + /// assert_eq!(COption::Some(COption::Some(6)), x.flatten()); + /// assert_eq!(COption::Some(6), x.flatten().flatten()); + /// ``` + #[inline] + pub fn flatten(self) -> COption { + self.and_then(convert::identity) + } +} + +impl From> for COption { + fn from(option: Option) -> Self { + match option { + Some(value) => COption::Some(value), + None => COption::None, + } + } +} + +impl Into> for COption { + fn into(self) -> Option { + match self { + COption::Some(value) => Some(value), + COption::None => None, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use solana_sdk::pubkey::Pubkey; + + #[test] + fn test_from_rust_option() { + let option = Some(99u64); + let c_option: COption = option.into(); + assert_eq!(c_option, COption::Some(99u64)); + let expected = c_option.into(); + assert_eq!(option, expected); + + let option = None; + let c_option: COption = option.into(); + assert_eq!(c_option, COption::None); + let expected = c_option.into(); + assert_eq!(option, expected); + } + + #[test] + fn test_coption_packing() { + // Solana Pubkey + let option_pubkey = COption::Some(Pubkey::new(&[2u8; 32])); + let expected_size = mem::size_of::() + mem::size_of::(); + let mut output = vec![0u8; expected_size]; + let mut cursor = 0; + option_pubkey.pack(&mut output, &mut cursor); + + let mut expected = vec![1u8]; + expected.extend_from_slice(&[2u8; 32]); + assert_eq!(output, expected); + + let mut cursor = 0; + let unpacked = COption::unpack_or(&expected, &mut cursor, "Error".to_string()).unwrap(); + assert_eq!(unpacked, option_pubkey); + + let option_pubkey: COption = COption::None; + let expected_size = mem::size_of::(); + let mut output = vec![0u8; expected_size]; + let mut cursor = 0; + option_pubkey.pack(&mut output, &mut cursor); + + let expected = vec![0u8]; + assert_eq!(output, expected); + + let mut cursor = 0; + let unpacked = COption::unpack_or(&expected, &mut cursor, "Error".to_string()).unwrap(); + assert_eq!(unpacked, option_pubkey); + + // u64 + let option_pubkey = COption::Some(99u64); + let expected_size = mem::size_of::() + mem::size_of::(); + let mut output = vec![0u8; expected_size]; + let mut cursor = 0; + option_pubkey.pack(&mut output, &mut cursor); + + let mut expected = vec![1u8]; + expected.extend_from_slice(&[99, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(output, expected); + + let mut cursor = 0; + let unpacked = COption::unpack_or(&expected, &mut cursor, "Error".to_string()).unwrap(); + assert_eq!(unpacked, option_pubkey); + + let option_pubkey: COption = COption::None; + let expected_size = mem::size_of::(); + let mut output = vec![0u8; expected_size]; + let mut cursor = 0; + option_pubkey.pack(&mut output, &mut cursor); + + let expected = vec![0u8]; + assert_eq!(output, expected); + + let mut cursor = 0; + let unpacked = COption::unpack_or(&expected, &mut cursor, "Error".to_string()).unwrap(); + assert_eq!(unpacked, option_pubkey); + } +} diff --git a/program/src/processor.rs b/program/src/processor.rs new file mode 100644 index 0000000..d8baa68 --- /dev/null +++ b/program/src/processor.rs @@ -0,0 +1,3128 @@ +//! Program state processor + +#![cfg(feature = "program")] + +use crate::{ + error::TokenError, + instruction::{is_valid_signer_index, AuthorityType, TokenInstruction}, + option::COption, + state::{self, Account, AccountState, IsInitialized, Mint, Multisig}, +}; +use num_traits::FromPrimitive; +use solana_sdk::{ + account_info::{next_account_info, AccountInfo}, + decode_error::DecodeError, + entrypoint::ProgramResult, + info, + program_error::{PrintProgramError, ProgramError}, + pubkey::Pubkey, +}; +use std::mem::size_of; + +/// Program state handler. +pub struct Processor {} +impl Processor { + /// Processes an [InitializeMint](enum.TokenInstruction.html) instruction. + pub fn process_initialize_mint( + accounts: &[AccountInfo], + decimals: u8, + mint_authority: COption, + freeze_authority: COption, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let mint_info = next_account_info(account_info_iter)?; + + let mut mint_info_data = mint_info.data.borrow_mut(); + let mut mint: &mut Mint = state::unpack_unchecked(&mut mint_info_data)?; + if mint.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } + + if mint_authority.is_none() { + return Err(TokenError::OwnerRequiredIfNoInitialSupply.into()); + } + + mint.mint_authority = mint_authority; + mint.decimals = decimals; + mint.is_initialized = true; + mint.freeze_authority = freeze_authority; + + Ok(()) + } + + /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. + pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let new_account_info = next_account_info(account_info_iter)?; + let mint_info = next_account_info(account_info_iter)?; + let owner_info = next_account_info(account_info_iter)?; + + let mut new_account_data = new_account_info.data.borrow_mut(); + let mut account: &mut Account = state::unpack_unchecked(&mut new_account_data)?; + if account.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } + + account.mint = *mint_info.key; + account.owner = *owner_info.key; + account.delegate = COption::None; + account.delegated_amount = 0; + account.state = AccountState::Initialized; + if *mint_info.key == crate::native_mint::id() { + account.is_native = true; + account.amount = new_account_info.lamports(); + } else { + account.is_native = false; + account.amount = 0; + }; + + Ok(()) + } + + /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. + pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let multisig_info = next_account_info(account_info_iter)?; + let mut multisig_account_data = multisig_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack_unchecked(&mut multisig_account_data)?; + if multisig.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } + + let signer_infos = account_info_iter.as_slice(); + multisig.m = m; + multisig.n = signer_infos.len() as u8; + if !is_valid_signer_index(multisig.n as usize) { + return Err(TokenError::InvalidNumberOfProvidedSigners.into()); + } + if !is_valid_signer_index(multisig.m as usize) { + return Err(TokenError::InvalidNumberOfRequiredSigners.into()); + } + for (i, signer_info) in signer_infos.iter().enumerate() { + multisig.signers[i] = *signer_info.key; + } + multisig.is_initialized = true; + + Ok(()) + } + + /// Processes a [Transfer](enum.TokenInstruction.html) instruction. + pub fn process_transfer( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + let dest_account_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + if source_account_info.key == dest_account_info.key { + return Ok(()); + } + + let mut source_data = source_account_info.data.borrow_mut(); + let mut source_account: &mut Account = state::unpack(&mut source_data)?; + let mut dest_data = dest_account_info.data.borrow_mut(); + let mut dest_account: &mut Account = state::unpack(&mut dest_data)?; + + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + if source_account.mint != dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } + if source_account.is_frozen() || dest_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + match source_account.delegate { + COption::Some(ref delegate) if authority_info.key == delegate => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount -= amount; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?, + }; + + source_account.amount -= amount; + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + + if source_account.is_native { + **source_account_info.lamports.borrow_mut() -= amount; + **dest_account_info.lamports.borrow_mut() += amount; + } + + Ok(()) + } + + /// Processes an [Approve](enum.TokenInstruction.html) instruction. + pub fn process_approve( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let mut source_account: &mut Account = state::unpack(&mut source_data)?; + let delegate_info = next_account_info(account_info_iter)?; + let owner_info = next_account_info(account_info_iter)?; + + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + Self::validate_owner( + program_id, + &source_account.owner, + owner_info, + account_info_iter.as_slice(), + )?; + + source_account.delegate = COption::Some(*delegate_info.key); + source_account.delegated_amount = amount; + + Ok(()) + } + + /// Processes an [Revoke](enum.TokenInstruction.html) instruction. + pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let mut source_account: &mut Account = state::unpack(&mut source_data)?; + let owner_info = next_account_info(account_info_iter)?; + + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + Self::validate_owner( + program_id, + &source_account.owner, + owner_info, + account_info_iter.as_slice(), + )?; + + source_account.delegate = COption::None; + source_account.delegated_amount = 0; + + Ok(()) + } + + /// Processes a [SetAuthority](enum.TokenInstruction.html) instruction. + pub fn process_set_authority( + program_id: &Pubkey, + accounts: &[AccountInfo], + authority_type: AuthorityType, + new_authority: COption, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let account_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + if account_info.data_len() == size_of::() { + let mut account_data = account_info.data.borrow_mut(); + let mut account: &mut Account = state::unpack(&mut account_data)?; + + if account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + match authority_type { + AuthorityType::AccountHolder => { + Self::validate_owner( + program_id, + &account.owner, + authority_info, + account_info_iter.as_slice(), + )?; + + if let COption::Some(authority) = new_authority { + account.owner = authority; + } else { + return Err(TokenError::InvalidInstruction.into()); + } + } + AuthorityType::CloseAccount => { + let authority = account.close_authority.unwrap_or(account.owner); + Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + )?; + account.close_authority = new_authority; + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); + } + } + } else if account_info.data_len() == size_of::() { + let mut account_data = account_info.data.borrow_mut(); + let mut mint: &mut Mint = state::unpack(&mut account_data)?; + + match authority_type { + AuthorityType::MintTokens => { + // Once a mint's supply is fixed, it cannot be undone by setting a new + // mint_authority + let mint_authority = mint + .mint_authority + .ok_or(Into::::into(TokenError::FixedSupply))?; + Self::validate_owner( + program_id, + &mint_authority, + authority_info, + account_info_iter.as_slice(), + )?; + mint.mint_authority = new_authority; + } + AuthorityType::FreezeAccount => { + // Once a mint's freeze authority is disabled, it cannot be re-enabled by + // setting a new freeze_authority + let freeze_authority = mint + .freeze_authority + .ok_or(Into::::into(TokenError::MintCannotFreeze))?; + Self::validate_owner( + program_id, + &freeze_authority, + authority_info, + account_info_iter.as_slice(), + )?; + mint.freeze_authority = new_authority; + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); + } + } + } else { + return Err(ProgramError::InvalidArgument); + } + + Ok(()) + } + + /// Processes a [MintTo](enum.TokenInstruction.html) instruction. + pub fn process_mint_to( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let mint_info = next_account_info(account_info_iter)?; + let dest_account_info = next_account_info(account_info_iter)?; + let owner_info = next_account_info(account_info_iter)?; + + let mut dest_account_data = dest_account_info.data.borrow_mut(); + let mut dest_account: &mut Account = state::unpack(&mut dest_account_data)?; + + if dest_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + if dest_account.is_native { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key != &dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mut mint_info_data = mint_info.data.borrow_mut(); + let mint: &mut Mint = state::unpack(&mut mint_info_data)?; + + match mint.mint_authority { + COption::Some(mint_authority) => { + Self::validate_owner( + program_id, + &mint_authority, + owner_info, + account_info_iter.as_slice(), + )?; + } + COption::None => { + return Err(TokenError::FixedSupply.into()); + } + } + + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + + Ok(()) + } + + /// Processes a [Burn](enum.TokenInstruction.html) instruction. + pub fn process_burn( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let source_account: &mut Account = state::unpack(&mut source_data)?; + + if source_account.is_native { + return Err(TokenError::NativeNotSupported.into()); + } + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + match source_account.delegate { + COption::Some(ref delegate) if authority_info.key == delegate => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; + + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount -= amount; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?, + } + + source_account.amount -= amount; + + Ok(()) + } + + /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. + pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + let dest_account_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let source_account: &mut Account = state::unpack(&mut source_data)?; + + if !source_account.is_native && source_account.amount != 0 { + return Err(TokenError::NonNativeHasBalance.into()); + } + + let authority = source_account + .close_authority + .unwrap_or(source_account.owner); + Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + )?; + + **dest_account_info.lamports.borrow_mut() += source_account_info.lamports(); + **source_account_info.lamports.borrow_mut() = 0; + source_account.amount = 0; + + Ok(()) + } + + /// Processes a [FreezeAccount](enum.TokenInstruction.html) or a + /// [ThawAccount](enum.TokenInstruction.html) instruction. + pub fn process_toggle_freeze_account( + program_id: &Pubkey, + accounts: &[AccountInfo], + freeze: bool, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + let mint_info = next_account_info(account_info_iter)?; + let authority_info = next_account_info(account_info_iter)?; + + let mut source_data = source_account_info.data.borrow_mut(); + let source_account: &mut Account = state::unpack(&mut source_data)?; + + if source_account.is_native { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { + return Err(TokenError::InvalidState.into()); + } + + let mut mint_info_data = mint_info.data.borrow_mut(); + let mint: &mut Mint = state::unpack(&mut mint_info_data)?; + + match mint.freeze_authority { + COption::Some(authority) => { + Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + )?; + } + COption::None => { + return Err(TokenError::MintCannotFreeze.into()); + } + } + + source_account.state = if freeze { + AccountState::Frozen + } else { + AccountState::Initialized + }; + + Ok(()) + } + + /// Processes an [Instruction](enum.Instruction.html). + pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { + let instruction = TokenInstruction::unpack(input)?; + + match instruction { + TokenInstruction::InitializeMint { + decimals, + mint_authority, + freeze_authority, + } => { + info!("Instruction: InitializeMint"); + Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority) + } + TokenInstruction::InitializeAccount => { + info!("Instruction: InitializeAccount"); + Self::process_initialize_account(accounts) + } + TokenInstruction::InitializeMultisig { m } => { + info!("Instruction: InitializeMultisig"); + Self::process_initialize_multisig(accounts, m) + } + TokenInstruction::Transfer { amount } => { + info!("Instruction: Transfer"); + Self::process_transfer(program_id, accounts, amount) + } + TokenInstruction::Approve { amount } => { + info!("Instruction: Approve"); + Self::process_approve(program_id, accounts, amount) + } + TokenInstruction::Revoke => { + info!("Instruction: Revoke"); + Self::process_revoke(program_id, accounts) + } + TokenInstruction::SetAuthority { + authority_type, + new_authority, + } => { + info!("Instruction: SetAuthority"); + Self::process_set_authority(program_id, accounts, authority_type, new_authority) + } + TokenInstruction::MintTo { amount } => { + info!("Instruction: MintTo"); + Self::process_mint_to(program_id, accounts, amount) + } + TokenInstruction::Burn { amount } => { + info!("Instruction: Burn"); + Self::process_burn(program_id, accounts, amount) + } + TokenInstruction::CloseAccount => { + info!("Instruction: CloseAccount"); + Self::process_close_account(program_id, accounts) + } + TokenInstruction::FreezeAccount => { + info!("Instruction: FreezeAccount"); + Self::process_toggle_freeze_account(program_id, accounts, true) + } + TokenInstruction::ThawAccount => { + info!("Instruction: FreezeAccount"); + Self::process_toggle_freeze_account(program_id, accounts, false) + } + } + } + + /// Validates owner(s) are present + pub fn validate_owner( + program_id: &Pubkey, + expected_owner: &Pubkey, + owner_account_info: &AccountInfo, + signers: &[AccountInfo], + ) -> ProgramResult { + if expected_owner != owner_account_info.key { + return Err(TokenError::OwnerMismatch.into()); + } + if program_id == owner_account_info.owner + && owner_account_info.data_len() == std::mem::size_of::() + { + let mut owner_data = owner_account_info.data.borrow_mut(); + let multisig: &mut Multisig = state::unpack(&mut owner_data)?; + let mut num_signers = 0; + for signer in signers.iter() { + if multisig.signers[0..multisig.n as usize].contains(signer.key) { + if !signer.is_signer { + return Err(ProgramError::MissingRequiredSignature); + } + num_signers += 1; + } + } + if num_signers < multisig.m { + return Err(ProgramError::MissingRequiredSignature); + } + } else if !owner_account_info.is_signer { + return Err(ProgramError::MissingRequiredSignature); + } + Ok(()) + } +} + +impl PrintProgramError for TokenError { + fn print(&self) + where + E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, + { + match self { + TokenError::InsufficientFunds => info!("Error: insufficient funds"), + TokenError::MintMismatch => info!("Error: Account not associated with this Mint"), + TokenError::OwnerMismatch => info!("Error: owner does not match"), + TokenError::FixedSupply => info!("Error: the total supply of this token is fixed"), + TokenError::AlreadyInUse => info!("Error: account or token already in use"), + TokenError::OwnerRequiredIfNoInitialSupply => { + info!("Error: An owner is required if supply is zero") + } + TokenError::InvalidNumberOfProvidedSigners => { + info!("Error: Invalid number of provided signers") + } + TokenError::InvalidNumberOfRequiredSigners => { + info!("Error: Invalid number of required signers") + } + TokenError::UninitializedState => info!("Error: State is uninitialized"), + TokenError::NativeNotSupported => { + info!("Error: Instruction does not support native tokens") + } + TokenError::NonNativeHasBalance => { + info!("Error: Non-native account can only be closed if its balance is zero") + } + TokenError::InvalidInstruction => info!("Error: Invalid instruction"), + TokenError::InvalidState => info!("Error: Invalid account state for operation"), + TokenError::Overflow => info!("Error: Operation overflowed"), + TokenError::AuthorityTypeNotSupported => { + info!("Error: Account does not support specified authority type") + } + TokenError::MintCannotFreeze => info!("Error: This token mint cannot freeze accounts"), + TokenError::AccountFrozen => info!("Error: Account is frozen"), + } + } +} + +// Pull in syscall stubs when building for non-BPF targets +#[cfg(not(target_arch = "bpf"))] +solana_sdk::program_stubs!(); + +#[cfg(test)] +mod tests { + use super::*; + use crate::instruction::{ + approve, burn, close_account, freeze_account, initialize_account, initialize_mint, + initialize_multisig, mint_to, revoke, set_authority, thaw_account, transfer, MAX_SIGNERS, + }; + use solana_sdk::{ + account::Account as SolanaAccount, account_info::create_is_signer_account_infos, + clock::Epoch, instruction::Instruction, + }; + + fn pubkey_rand() -> Pubkey { + Pubkey::new(&rand::random::<[u8; 32]>()) + } + + fn do_process_instruction( + instruction: Instruction, + accounts: Vec<&mut SolanaAccount>, + ) -> ProgramResult { + let mut meta = instruction + .accounts + .iter() + .zip(accounts) + .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) + .collect::>(); + + let account_infos = create_is_signer_account_infos(&mut meta); + Processor::process(&instruction.program_id, &account_infos, &instruction.data) + } + + fn return_token_error_as_program_error() -> ProgramError { + TokenError::MintMismatch.into() + } + + #[test] + fn test_print_error() { + let error = return_token_error_as_program_error(); + error.print::(); + } + + #[test] + #[should_panic(expected = "Custom(1)")] + fn test_error_unwrap() { + Err::<(), ProgramError>(return_token_error_as_program_error()).unwrap(); + } + + #[test] + fn test_unique_account_sizes() { + assert_ne!(size_of::(), 0); + assert_ne!(size_of::(), size_of::()); + assert_ne!(size_of::(), size_of::()); + assert_ne!(size_of::(), 0); + assert_ne!(size_of::(), size_of::()); + assert_ne!(size_of::(), 0); + } + + #[test] + fn test_initialize_mint() { + let program_id = pubkey_rand(); + let owner_key = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + + // mint_authority not provided + let mut instruction = initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(); + instruction.data = TokenInstruction::InitializeMint { + mint_authority: COption::None, + freeze_authority: COption::None, + decimals: 2, + } + .pack() + .unwrap(); + assert_eq!( + Err(TokenError::OwnerRequiredIfNoInitialSupply.into()), + do_process_instruction(instruction, vec![&mut mint_account]) + ); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // create twice + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), + vec![&mut mint_account] + ) + ); + + // create another mint that can freeze + do_process_instruction( + initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account], + ) + .unwrap(); + let mint2: &mut Mint = state::unpack(&mut mint2_account.data).unwrap(); + assert_eq!(mint2.freeze_authority, COption::Some(owner_key)); + } + + #[test] + fn test_initialize_mint_account() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create twice + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + } + + #[test] + fn test_transfer() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let delegate_key = pubkey_rand(); + let mut delegate_account = SolanaAccount::default(); + let mismatch_key = pubkey_rand(); + let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // create new mint & mint to account + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // missing signer + let mut instruction = transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // mismatch mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &mismatch_key, + &owner_key, + &[], + 1000 + ) + .unwrap(), + vec![ + &mut account_account, + &mut mismatch_account, + &mut owner_account, + ], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner2_key, + &[], + 1000 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // transfer + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // transfer half back + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // transfer rest + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // transfer to self + { + let instruction = transfer( + &program_id, + &account_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(); + let account_account_info = AccountInfo::from(( + &instruction.accounts[0].pubkey, + instruction.accounts[0].is_signer, + &mut account_account, + )); + let owner_account_info = AccountInfo::from(( + &instruction.accounts[2].pubkey, + instruction.accounts[2].is_signer, + &mut owner_account, + )); + Processor::process( + &instruction.program_id, + &[ + account_account_info.clone(), + account_account_info, + owner_account_info, + ], + &instruction.data, + ) + .unwrap() + } + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, 1000); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // transfer via delegate + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + .unwrap(); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + + // transfer rest + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 900, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds in source account via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + } + + #[test] + fn test_mintable_token_with_zero_supply() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut owner_account, &mut mint_account], + ) + .unwrap(); + + // create mint-able token with zero supply + let decimals = 2; + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + assert_eq!( + *mint, + Mint { + mint_authority: COption::Some(owner_key), + decimals, + is_initialized: true, + freeze_authority: COption::None, + } + ); + + // mint to + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(dest_account.amount, 42); + } + + #[test] + fn test_approve() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let delegate_key = pubkey_rand(); + let mut delegate_account = SolanaAccount::default(); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut owner_account, &mut mint_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut owner_account, &mut mint_account], + ) + .unwrap(); + + // create new mint & mint to account + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut account_account], + ) + .unwrap(); + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // missing signer + let mut instruction = approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // no owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner2_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner2_account, + ], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // revoke delegate + do_process_instruction( + revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + } + + #[test] + fn test_set_authority() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let owner3_key = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + + // invalid account + assert_eq!( + Err(TokenError::UninitializedState.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountHolder, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner_key), + AuthorityType::AccountHolder, + &owner2_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + ); + + // owner did not sign + let mut instruction = set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountHolder, + &owner_key, + &[], + ) + .unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],) + ); + + // wrong authority type + assert_eq!( + Err(TokenError::AuthorityTypeNotSupported.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // account owner may not be set to None + assert_eq!( + Err(TokenError::InvalidInstruction.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + None, + AuthorityType::AccountHolder, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // set owner + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountHolder, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // set close_authority + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::CloseAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + .unwrap(); + + // close_authority may be set to None + do_process_instruction( + set_authority( + &program_id, + &account_key, + None, + AuthorityType::CloseAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + .unwrap(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // wrong owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner3_key), + AuthorityType::MintTokens, + &owner2_key, + &[] + ) + .unwrap(), + vec![&mut mint_account, &mut owner2_account], + ) + ); + + // owner did not sign + let mut instruction = set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],) + ); + + // cannot freeze + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + ); + + // set owner + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + .unwrap(); + + // set owner to None + do_process_instruction( + set_authority( + &program_id, + &mint_key, + None, + AuthorityType::MintTokens, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner2_account], + ) + .unwrap(); + + // test unsetting mint_authority is one-way operation + assert_eq!( + Err(TokenError::FixedSupply.into()), + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + ); + + // create mint with owner and freeze_authority + do_process_instruction( + initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account], + ) + .unwrap(); + + // set freeze_authority + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner_account], + ) + .unwrap(); + + // test unsetting freeze_authority is one-way operation + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + None, + AuthorityType::FreezeAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner2_account], + ) + .unwrap(); + + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner2_account], + ) + ); + } + + #[test] + fn test_mint_to() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let mismatch_key = pubkey_rand(); + let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + let uninitialized_key = pubkey_rand(); + let mut uninitialized_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // mint to + do_process_instruction( + mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + .unwrap(); + + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let dest_account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert_eq!(dest_account.amount, 42); + + // missing signer + let mut instruction = + mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + ); + + // mismatch account + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // uninitialized destination account + assert_eq!( + Err(TokenError::UninitializedState.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &uninitialized_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![ + &mut mint_account, + &mut uninitialized_account, + &mut owner_account, + ], + ) + ); + + // unset mint_authority and test minting fails + do_process_instruction( + set_authority( + &program_id, + &mint_key, + None, + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + .unwrap(); + assert_eq!( + Err(TokenError::FixedSupply.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + ); + } + + #[test] + fn test_burn() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let delegate_key = pubkey_rand(); + let mut delegate_account = SolanaAccount::default(); + let mismatch_key = pubkey_rand(); + let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // missing signer + let mut instruction = burn(&program_id, &account_key, &delegate_key, &[], 42).unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + instruction, + vec![&mut account_account, &mut delegate_account], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner2_key, &[], 42).unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + ); + + // burn + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, 1000 - 42); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 84, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // not a delegate of source account + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // burn via delegate + do_process_instruction( + burn(&program_id, &account_key, &delegate_key, &[], 84).unwrap(), + vec![&mut account_account, &mut delegate_account], + ) + .unwrap(); + + // match + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, 1000 - 42 - 84); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn(&program_id, &account_key, &delegate_key, &[], 100).unwrap(), + vec![&mut account_account, &mut delegate_account], + ) + ); + } + + #[test] + fn test_multisig() { + let program_id = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let account_key = pubkey_rand(); + let mut account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let multisig_key = pubkey_rand(); + let mut multisig_account = SolanaAccount::new(0, size_of::(), &program_id); + let multisig_delegate_key = pubkey_rand(); + let mut multisig_delegate_account = + SolanaAccount::new(0, size_of::(), &program_id); + let signer_keys = vec![pubkey_rand(); MAX_SIGNERS]; + let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().map(|key| key).collect(); + let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; + + // single signer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // multiple signer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig( + &program_id, + &multisig_delegate_key, + &signer_key_refs, + MAX_SIGNERS as u8, + ) + .unwrap(), + vec![ + &mut multisig_delegate_account, + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // create account with multisig owner + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), + vec![&mut account, &mut mint_account, &mut multisig_account], + ) + .unwrap(); + + // create another account with multisig owner + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &mint_key, + &multisig_delegate_key, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut multisig_account, + ], + ) + .unwrap(); + + // create new mint with multisig owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &multisig_key, + &[&signer_keys[0]], + 1000, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // approve + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + approve( + &program_id, + &account_key, + &multisig_delegate_key, + &multisig_key, + &[&signer_keys[0]], + 100, + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_delegate_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // transfer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut account2_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // transfer via delegate + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &multisig_delegate_key, + &signer_key_refs, + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut account2_account, + &mut multisig_delegate_account, + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // mint to + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // burn + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + burn( + &program_id, + &account_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // burn via delegate + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + burn( + &program_id, + &account_key, + &multisig_delegate_key, + &signer_key_refs, + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_delegate_account, + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // freeze account + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let mint2_key = pubkey_rand(); + let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint2_account, + &mut owner_account, + ], + ) + .unwrap(); + do_process_instruction( + initialize_mint( + &program_id, + &mint2_key, + &multisig_key, + Some(&multisig_key), + 2, + ) + .unwrap(), + vec![&mut mint2_account], + ) + .unwrap(); + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint2_key, + &account3_key, + &multisig_key, + &[&signer_keys[0]], + 1000, + ) + .unwrap(), + vec![ + &mut mint2_account, + &mut account3_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + freeze_account( + &program_id, + &account3_key, + &mint2_key, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut account3_account, + &mut mint2_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // do SetAuthority on mint + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::MintTokens, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut mint_account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // do SetAuthority on account + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner_key), + AuthorityType::AccountHolder, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_account, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + } + + #[test] + fn test_validate_owner() { + let program_id = pubkey_rand(); + let owner_key = pubkey_rand(); + let mut signer_keys = [Pubkey::default(); MAX_SIGNERS]; + for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) { + *signer_key = pubkey_rand(); + } + let mut signer_lamports = 0; + let mut signer_data = vec![]; + let mut signers = vec![ + AccountInfo::new( + &owner_key, + true, + false, + &mut signer_lamports, + &mut signer_data, + &program_id, + false, + Epoch::default(), + ); + MAX_SIGNERS + 1 + ]; + for (signer, key) in signers.iter_mut().zip(&signer_keys) { + signer.key = key; + } + let mut lamports = 0; + let mut data = vec![0; size_of::()]; + let mut multisig: &mut Multisig = state::unpack_unchecked(&mut data).unwrap(); + multisig.m = MAX_SIGNERS as u8; + multisig.n = MAX_SIGNERS as u8; + multisig.signers = signer_keys; + multisig.is_initialized = true; + let owner_account_info = AccountInfo::new( + &owner_key, + false, + false, + &mut lamports, + &mut data, + &program_id, + false, + Epoch::default(), + ); + + // full 11 of 11 + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); + + // 1 of 11 + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 1; + } + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); + + // 2:1 + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 1; + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) + ); + + // 0:11 + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 0; + multisig.n = 11; + } + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); + + // 2:11 but 0 provided + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 11; + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &[]) + ); + // 2:11 but 1 provided + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 11; + } + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[0..1]) + ); + + // 2:11, 2 from middle provided + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 11; + } + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[5..7]) + .unwrap(); + + // 11:11, one is not a signer + { + let mut data_ref_mut = owner_account_info.data.borrow_mut(); + let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); + multisig.m = 2; + multisig.n = 11; + } + signers[5].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) + ); + signers[5].is_signer = true; + } + + #[test] + fn test_close_account() { + let program_id = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(2, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(2, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + + // uninitialized + assert_eq!( + Err(TokenError::UninitializedState.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + ); + + // initialize and mint to non-native account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account.amount, 2); + + // close non-native account with balance + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + ); + assert_eq!(account_account.lamports, 42); + + // empty account + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // wrong owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + ); + + // close account + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap(); + assert_eq!(account_account.lamports, 0); + assert_eq!(account.amount, 0); + assert_eq!(account3_account.lamports, 44); + + // fund and initialize new non-native account to test close authority + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::new(42, size_of::(), &program_id); + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + account_account.lamports = 2; + + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::CloseAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // account owner cannot authorize close if close_authority is set + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + ); + + // close non-native account with close_authority + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, 0); + assert_eq!(account.amount, 0); + assert_eq!(account3_account.lamports, 46); + + // close native account + do_process_instruction( + close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account2_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack_unchecked(&mut account2_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account_account.lamports, 0); + assert_eq!(account.amount, 0); + assert_eq!(account3_account.lamports, 48); + } + + #[test] + fn test_native_token() { + let program_id = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(2, size_of::(), &program_id); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new(2, 0, &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account.amount, 42); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account.amount, 2); + + // mint_to unsupported + assert_eq!( + Err(TokenError::NativeNotSupported.into()), + do_process_instruction( + mint_to( + &program_id, + &crate::native_mint::id(), + &account_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + + // burn unsupported + assert_eq!( + Err(TokenError::NativeNotSupported.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // initialize native account + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 40, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account_account.lamports, 2); + assert_eq!(account.amount, 2); + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account2_account.lamports, 42); + assert_eq!(account.amount, 42); + + // close native account + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap(); + assert!(account.is_native); + assert_eq!(account_account.lamports, 0); + assert_eq!(account.amount, 0); + assert_eq!(account3_account.lamports, 4); + } + + #[test] + fn test_overflow() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_owner_key = pubkey_rand(); + let mut mint_owner_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create victim account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner2_account, + ], + ) + .unwrap(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // mint the max to attacker + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &mint_owner_key, + &[], + 42, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // mint the max to victum + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // mint one more + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + ); + + // mint back to large amount + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + account.amount = 0; + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // transfer to burn victim + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner2_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner2_account, + ], + ) + ); + } + + #[test] + fn test_frozen() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // create new mint and fund first account + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // no transfer if either account is frozen + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + account.state = AccountState::Frozen; + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + account.state = AccountState::Initialized; + let account2: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + account2.state = AccountState::Frozen; + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // no approve if account is frozen + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + account.state = AccountState::Frozen; + let delegate_key = pubkey_rand(); + let mut delegate_account = SolanaAccount::default(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // no revoke if account is frozen + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + account.delegate = COption::Some(delegate_key); + account.delegated_amount = 100; + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut owner_account,], + ) + ); + + // no set authority if account is frozen + let new_owner_key = pubkey_rand(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&new_owner_key), + AuthorityType::AccountHolder, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner_account,], + ) + ); + + // no mint_to if destination account is frozen + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 100).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account,], + ) + ); + + // no burn if account is frozen + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + burn(&program_id, &account_key, &owner_key, &[], 100).unwrap(), + vec![&mut account_account, &mut owner_account,], + ) + ); + } + + #[test] + fn test_freeze_account() { + let program_id = pubkey_rand(); + let account_key = pubkey_rand(); + let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let account_owner_key = pubkey_rand(); + let mut account_owner_account = SolanaAccount::default(); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = pubkey_rand(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = pubkey_rand(); + let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &account_owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut account_owner_account, + ], + ) + .unwrap(); + + // create new mint with owner different from account owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // mint cannot freeze + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // missing freeze_authority + let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + mint.freeze_authority = COption::Some(owner_key); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + freeze_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // check explicit thaw + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // freeze + do_process_instruction( + freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.state, AccountState::Frozen); + + // check explicit freeze + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // check thaw authority + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // thaw + do_process_instruction( + thaw_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.state, AccountState::Initialized); + } +} diff --git a/program/src/state.rs b/program/src/state.rs new file mode 100644 index 0000000..423fa64 --- /dev/null +++ b/program/src/state.rs @@ -0,0 +1,122 @@ +//! State transition types + +use crate::{error::TokenError, instruction::MAX_SIGNERS, option::COption}; +use solana_sdk::{program_error::ProgramError, pubkey::Pubkey}; +use std::mem::size_of; + +/// Mint data. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Mint { + /// Optional authority used to mint new tokens. The mint authority may only be provided during + /// mint creation. If no mint authority is present then the mint has a fixed supply and no + /// further tokens may be minted. + pub mint_authority: COption, + /// Number of base 10 digits to the right of the decimal place. + pub decimals: u8, + /// Is `true` if this structure has been initialized + pub is_initialized: bool, + /// Optional authority to freeze token accounts. + pub freeze_authority: COption, +} +impl IsInitialized for Mint { + fn is_initialized(&self) -> bool { + self.is_initialized + } +} + +/// Account data. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Account { + /// The mint associated with this account + pub mint: Pubkey, + /// The owner of this account. + pub owner: Pubkey, + /// The amount of tokens this account holds. + pub amount: u64, + /// If `delegate` is `Some` then `delegated_amount` represents + /// the amount authorized by the delegate + pub delegate: COption, + /// The account's state + pub state: AccountState, + /// Is this a native token + pub is_native: bool, + /// The amount delegated + pub delegated_amount: u64, + /// Optional authority to close the account. + pub close_authority: COption, +} +impl Account { + /// Checks if account is frozen + pub fn is_frozen(&self) -> bool { + self.state == AccountState::Frozen + } +} +impl IsInitialized for Account { + fn is_initialized(&self) -> bool { + self.state != AccountState::Uninitialized + } +} + +/// Account state. +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum AccountState { + /// Account is not yet initialized + Uninitialized, + /// Account is initialized; the account owner and/or delegate may perform permitted operations + /// on this account + Initialized, + /// Account has been frozen by the mint freeze authority. Neither the account owner nor + /// the delegate are able to perform operations on this account. + Frozen, +} + +impl Default for AccountState { + fn default() -> Self { + AccountState::Uninitialized + } +} + +/// Multisignature data. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Multisig { + /// Number of signers required + pub m: u8, + /// Number of valid signers + pub n: u8, + /// Is `true` if this structure has been initialized + pub is_initialized: bool, + /// Signer public keys + pub signers: [Pubkey; MAX_SIGNERS], +} +impl IsInitialized for Multisig { + fn is_initialized(&self) -> bool { + self.is_initialized + } +} + +/// Check is a token state is initialized +pub trait IsInitialized { + /// Is initialized + fn is_initialized(&self) -> bool; +} + +/// Unpacks a token state from a bytes buffer while assuring that the state is initialized. +pub fn unpack(input: &mut [u8]) -> Result<&mut T, ProgramError> { + let mut_ref: &mut T = unpack_unchecked(input)?; + if !mut_ref.is_initialized() { + return Err(TokenError::UninitializedState.into()); + } + Ok(mut_ref) +} +/// Unpacks a token state from a bytes buffer without checking that the state is initialized. +pub fn unpack_unchecked(input: &mut [u8]) -> Result<&mut T, ProgramError> { + if input.len() != size_of::() { + return Err(ProgramError::InvalidAccountData); + } + #[allow(clippy::cast_ptr_alignment)] + Ok(unsafe { &mut *(&mut input[0] as *mut u8 as *mut T) }) +} From 6df37af663069f6814b4092af05b3c09b5649998 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 26 Aug 2020 22:34:43 -0700 Subject: [PATCH 030/335] Update token.h --- program/inc/token.h | 219 +++++++++++++++++++++++++++++++++----------- 1 file changed, 163 insertions(+), 56 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index 38222c0..44f8423 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -21,6 +21,89 @@ */ #define Token_MIN_SIGNERS 1 +/** + * Account state. + */ +enum Token_AccountState +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + /** + * Account is not yet initialized + */ + Token_AccountState_Uninitialized, + /** + * Account is initialized; the account owner and/or delegate may perform permitted operations + * on this account + */ + Token_AccountState_Initialized, + /** + * Account has been frozen by the mint freeze authority. Neither the account owner nor + * the delegate are able to perform operations on this account. + */ + Token_AccountState_Frozen, +}; +#ifndef __cplusplus +typedef uint8_t Token_AccountState; +#endif // __cplusplus + +/** + * Specifies the authority type for SetAuthority instructions + */ +enum Token_AuthorityType +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + /** + * Authority to mint new tokens + */ + Token_AuthorityType_MintTokens, + /** + * Authority to freeze any account associated with the Mint + */ + Token_AuthorityType_FreezeAccount, + /** + * Holder of a given token account + */ + Token_AuthorityType_AccountHolder, + /** + * Authority to close a token account + */ + Token_AuthorityType_CloseAccount, +}; +#ifndef __cplusplus +typedef uint8_t Token_AuthorityType; +#endif // __cplusplus + +typedef uint8_t Token_Pubkey[32]; + +/** + * A C representation of Rust's `std::option::Option` + */ +typedef enum Token_COption_Pubkey_Tag { + /** + * No value + */ + Token_COption_Pubkey_None_Pubkey, + /** + * Some value `T` + */ + Token_COption_Pubkey_Some_Pubkey, +} Token_COption_Pubkey_Tag; + +typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { + Token_Pubkey _0; +} Token_COption_Pubkey_Token_Some_Body_Pubkey; + +typedef struct Token_COption_Pubkey { + Token_COption_Pubkey_Tag tag; + union { + Token_COption_Pubkey_Token_Some_Body_Pubkey some; + }; +} Token_COption_Pubkey; + /** * Instructions supported by the token program. */ @@ -35,11 +118,6 @@ typedef enum Token_TokenInstruction_Tag { * Accounts expected by this instruction: * * 0. `[writable]` The mint to initialize. - * 1. - * * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. - * * If supply is zero: `[]` The owner/multisignature of the mint. - * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if - * present then further minting is supported. * */ Token_TokenInstruction_InitializeMint, @@ -127,36 +205,34 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_Revoke, /** - * Sets a new owner of a mint or account. + * Sets a new authority of a mint or account. * * Accounts expected by this instruction: * - * * Single owner - * 0. `[writable]` The mint or account to change the owner of. - * 1. `[]` The new owner/delegate/multisignature. - * 2. `[signer]` The owner of the mint or account. + * * Single authority + * 0. `[writable]` The mint or account to change the authority of. + * 1. `[signer]` The current authority of the mint or account. * - * * Multisignature owner - * 0. `[writable]` The mint or account to change the owner of. - * 1. `[]` The new owner/delegate/multisignature. - * 2. `[]` The mint's or account's multisignature owner. + * * Multisignature authority + * 0. `[writable]` The mint or account to change the authority of. + * 1. `[]` The mint's or account's multisignature authority. * 3. ..3+M '[signer]' M signer accounts */ - Token_TokenInstruction_SetOwner, + Token_TokenInstruction_SetAuthority, /** * Mints new tokens to an account. The native mint does not support minting. * * Accounts expected by this instruction: * - * * Single owner + * * Single authority * 0. `[writable]` The mint. * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's owner. + * 2. `[signer]` The mint's minting authority. * - * * Multisignature owner + * * Multisignature authority * 0. `[writable]` The mint. * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature owner. + * 2. `[]` The mint's multisignature mint-tokens authority. * 3. ..3+M '[signer]' M signer accounts. */ Token_TokenInstruction_MintTo, @@ -194,17 +270,55 @@ typedef enum Token_TokenInstruction_Tag { * 3. ..3+M '[signer]' M signer accounts. */ Token_TokenInstruction_CloseAccount, + /** + * Freeze an Initialized account using the Mint's freeze_authority (if set). + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The account to freeze. + * 1. '[]' The token mint. + * 2. `[signer]` The mint freeze authority. + * + * * Multisignature owner + * 0. `[writable]` The account to freeze. + * 1. '[]' The token mint. + * 2. `[]` The mint's multisignature freeze authority. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_FreezeAccount, + /** + * Thaw a Frozen account using the Mint's freeze_authority (if set). + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The account to freeze. + * 1. '[]' The token mint. + * 2. `[signer]` The mint freeze authority. + * + * * Multisignature owner + * 0. `[writable]` The account to freeze. + * 1. '[]' The token mint. + * 2. `[]` The mint's multisignature freeze authority. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_ThawAccount, } Token_TokenInstruction_Tag; typedef struct Token_TokenInstruction_Token_InitializeMint_Body { - /** - * Initial amount of tokens to mint. - */ - uint64_t amount; /** * Number of base 10 digits to the right of the decimal place. */ uint8_t decimals; + /** + * The authority/multisignature to mint tokens. + */ + Token_Pubkey mint_authority; + /** + * The freeze authority/multisignature of the mint. + */ + Token_COption_Pubkey freeze_authority; } Token_TokenInstruction_Token_InitializeMint_Body; typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { @@ -228,6 +342,17 @@ typedef struct Token_TokenInstruction_Token_Approve_Body { uint64_t amount; } Token_TokenInstruction_Token_Approve_Body; +typedef struct Token_TokenInstruction_Token_SetAuthority_Body { + /** + * The type of authority to update. + */ + Token_AuthorityType authority_type; + /** + * The new authority + */ + Token_COption_Pubkey new_authority; +} Token_TokenInstruction_Token_SetAuthority_Body; + typedef struct Token_TokenInstruction_Token_MintTo_Body { /** * The amount of new tokens to mint. @@ -249,48 +374,22 @@ typedef struct Token_TokenInstruction { Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; Token_TokenInstruction_Token_Transfer_Body transfer; Token_TokenInstruction_Token_Approve_Body approve; + Token_TokenInstruction_Token_SetAuthority_Body set_authority; Token_TokenInstruction_Token_MintTo_Body mint_to; Token_TokenInstruction_Token_Burn_Body burn; }; } Token_TokenInstruction; -typedef uint8_t Token_Pubkey[32]; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_Pubkey_Tag { - /** - * No value - */ - Token_COption_Pubkey_None_Pubkey, - /** - * Some value `T` - */ - Token_COption_Pubkey_Some_Pubkey, -} Token_COption_Pubkey_Tag; - -typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { - Token_Pubkey _0; -} Token_COption_Pubkey_Token_Some_Body_Pubkey; - -typedef struct Token_COption_Pubkey { - Token_COption_Pubkey_Tag tag; - union { - Token_COption_Pubkey_Token_Some_Body_Pubkey some; - }; -} Token_COption_Pubkey; - /** * Mint data. */ typedef struct Token_Mint { /** - * Optional owner, used to mint new tokens. The owner may only - * be provided during mint creation. If no owner is present then the mint - * has a fixed supply and no further tokens may be minted. + * Optional authority used to mint new tokens. The mint authority may only be provided during + * mint creation. If no mint authority is present then the mint has a fixed supply and no + * further tokens may be minted. */ - Token_COption_Pubkey owner; + Token_COption_Pubkey mint_authority; /** * Number of base 10 digits to the right of the decimal place. */ @@ -299,6 +398,10 @@ typedef struct Token_Mint { * Is `true` if this structure has been initialized */ bool is_initialized; + /** + * Optional authority to freeze token accounts. + */ + Token_COption_Pubkey freeze_authority; } Token_Mint; /** @@ -323,9 +426,9 @@ typedef struct Token_Account { */ Token_COption_Pubkey delegate; /** - * Is `true` if this structure has been initialized + * The account's state */ - bool is_initialized; + Token_AccountState state; /** * Is this a native token */ @@ -334,6 +437,10 @@ typedef struct Token_Account { * The amount delegated */ uint64_t delegated_amount; + /** + * Optional authority to close the account. + */ + Token_COption_Pubkey close_authority; } Token_Account; /** From 4bfbd523dd7235ac42e906c71487c03c13a9c7e5 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 26 Aug 2020 22:58:42 -0700 Subject: [PATCH 031/335] InitializeMint's mint authority is no longer optional --- program/src/error.rs | 3 --- program/src/instruction.rs | 32 +++++++++++++++++--------------- program/src/processor.rs | 25 ++----------------------- 3 files changed, 19 insertions(+), 41 deletions(-) diff --git a/program/src/error.rs b/program/src/error.rs index cc7da55..a1d3152 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -22,9 +22,6 @@ pub enum TokenError { /// The account cannot be initialized because it is already being used. #[error("AlreadyInUse")] AlreadyInUse, - /// An owner is required if initial supply is zero. - #[error("An owner is required if supply is zero")] - OwnerRequiredIfNoInitialSupply, /// Invalid number of provided signers. #[error("Invalid number of provided signers")] InvalidNumberOfProvidedSigners, diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 96acf76..9c77516 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -30,8 +30,8 @@ pub enum TokenInstruction { InitializeMint { /// Number of base 10 digits to the right of the decimal place. decimals: u8, - /// The authority/multisignature to mint tokens. If present, further minting is supported. - mint_authority: COption, + /// The authority/multisignature to mint tokens. + mint_authority: Pubkey, /// The freeze authority/multisignature of the mint. freeze_authority: COption, }, @@ -226,7 +226,7 @@ impl TokenInstruction { } Ok(match input[0] { 0 => { - if input.len() < size_of::() + size_of::() + size_of::() { + if input.len() < size_of::() + size_of::() + size_of::() { return Err(TokenError::InvalidInstruction.into()); } let mut input_len = 0; @@ -235,11 +235,9 @@ impl TokenInstruction { let decimals = unsafe { *(&input[input_len] as *const u8) }; input_len += size_of::(); - let mint_authority = COption::unpack_or( - input, - &mut input_len, - Into::::into(TokenError::InvalidInstruction), - )?; + let mint_authority = unsafe { *(&input[input_len] as *const u8 as *const Pubkey) }; + input_len += size_of::(); + let freeze_authority = COption::unpack_or( input, &mut input_len, @@ -338,7 +336,11 @@ impl TokenInstruction { *value = *decimals; output_len += size_of::(); - mint_authority.pack(&mut output, &mut output_len); + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut Pubkey) }; + *value = *mint_authority; + output_len += size_of::(); + freeze_authority.pack(&mut output, &mut output_len); } Self::InitializeAccount => { @@ -468,10 +470,9 @@ pub fn initialize_mint( freeze_authority_pubkey: Option<&Pubkey>, decimals: u8, ) -> Result { - let mint_authority = COption::Some(*mint_authority_pubkey); let freeze_authority = freeze_authority_pubkey.cloned().into(); let data = TokenInstruction::InitializeMint { - mint_authority, + mint_authority: *mint_authority_pubkey, freeze_authority, decimals, } @@ -806,23 +807,24 @@ mod test { fn test_instruction_packing() { let check = TokenInstruction::InitializeMint { decimals: 2, - mint_authority: COption::None, + mint_authority: Pubkey::new(&[1u8; 32]), freeze_authority: COption::None, }; let packed = check.pack().unwrap(); - let expect = Vec::from([0u8, 2, 0, 0]); + let mut expect = Vec::from([0u8, 2]); + expect.extend_from_slice(&[1u8; 32]); + expect.extend_from_slice(&[0]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::InitializeMint { decimals: 2, - mint_authority: COption::Some(Pubkey::new(&[2u8; 32])), + mint_authority: Pubkey::new(&[2u8; 32]), freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), }; let packed = check.pack().unwrap(); let mut expect = vec![0u8, 2]; - expect.extend_from_slice(&[1]); expect.extend_from_slice(&[2u8; 32]); expect.extend_from_slice(&[1]); expect.extend_from_slice(&[3u8; 32]); diff --git a/program/src/processor.rs b/program/src/processor.rs index d8baa68..e4fe542 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -26,7 +26,7 @@ impl Processor { pub fn process_initialize_mint( accounts: &[AccountInfo], decimals: u8, - mint_authority: COption, + mint_authority: Pubkey, freeze_authority: COption, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -38,11 +38,7 @@ impl Processor { return Err(TokenError::AlreadyInUse.into()); } - if mint_authority.is_none() { - return Err(TokenError::OwnerRequiredIfNoInitialSupply.into()); - } - - mint.mint_authority = mint_authority; + mint.mint_authority = COption::Some(mint_authority); mint.decimals = decimals; mint.is_initialized = true; mint.freeze_authority = freeze_authority; @@ -616,9 +612,6 @@ impl PrintProgramError for TokenError { TokenError::OwnerMismatch => info!("Error: owner does not match"), TokenError::FixedSupply => info!("Error: the total supply of this token is fixed"), TokenError::AlreadyInUse => info!("Error: account or token already in use"), - TokenError::OwnerRequiredIfNoInitialSupply => { - info!("Error: An owner is required if supply is zero") - } TokenError::InvalidNumberOfProvidedSigners => { info!("Error: Invalid number of provided signers") } @@ -714,20 +707,6 @@ mod tests { let mint2_key = pubkey_rand(); let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); - // mint_authority not provided - let mut instruction = initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(); - instruction.data = TokenInstruction::InitializeMint { - mint_authority: COption::None, - freeze_authority: COption::None, - decimals: 2, - } - .pack() - .unwrap(); - assert_eq!( - Err(TokenError::OwnerRequiredIfNoInitialSupply.into()), - do_process_instruction(instruction, vec![&mut mint_account]) - ); - // create new mint do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), From a0c82625262a992ab189b09dadc20b3d1ad1cb7f Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 00:29:54 -0600 Subject: [PATCH 032/335] Pass rent_sysvar into init Instructions and check rent-exempt --- program/src/error.rs | 3 + program/src/instruction.rs | 15 +- program/src/processor.rs | 514 +++++++++++++++++++++++++++++-------- 3 files changed, 416 insertions(+), 116 deletions(-) diff --git a/program/src/error.rs b/program/src/error.rs index a1d3152..4a9e223 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -7,6 +7,9 @@ use thiserror::Error; /// Errors that may be returned by the Token program. #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] pub enum TokenError { + /// Lamport balance below rent-exempt threshold. + #[error("Lamport balance below rent-exempt threshold")] + NotRentExempt, /// Insufficient funds for the operation requested. #[error("Insufficient funds")] InsufficientFunds, diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 9c77516..79bd0a0 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -5,6 +5,7 @@ use solana_sdk::{ instruction::{AccountMeta, Instruction}, program_error::ProgramError, pubkey::Pubkey, + sysvar, }; use std::mem::size_of; @@ -26,6 +27,7 @@ pub enum TokenInstruction { /// Accounts expected by this instruction: /// /// 0. `[writable]` The mint to initialize. + /// 1. `[]` Rent sysvar /// InitializeMint { /// Number of base 10 digits to the right of the decimal place. @@ -47,6 +49,7 @@ pub enum TokenInstruction { /// 0. `[writable]` The account to initialize. /// 1. `[]` The mint this account will be associated with. /// 2. `[]` The new account's owner/multisignature. + /// 3. `[]` Rent sysvar InitializeAccount, /// Initializes a multisignature account with N provided signers. /// @@ -61,7 +64,8 @@ pub enum TokenInstruction { /// Accounts expected by this instruction: /// /// 0. `[writable]` The multisignature account to initialize. - /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + /// 2. `[]` Rent sysvar + /// 3. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. InitializeMultisig { /// The number of signers (M) required to validate this multisignature account. m: u8, @@ -478,7 +482,10 @@ pub fn initialize_mint( } .pack()?; - let accounts = vec![AccountMeta::new(*mint_pubkey, false)]; + let accounts = vec![ + AccountMeta::new(*mint_pubkey, false), + AccountMeta::new_readonly(sysvar::rent::id(), false), + ]; Ok(Instruction { program_id: *token_program_id, @@ -500,6 +507,7 @@ pub fn initialize_account( AccountMeta::new(*account_pubkey, false), AccountMeta::new_readonly(*mint_pubkey, false), AccountMeta::new_readonly(*owner_pubkey, false), + AccountMeta::new_readonly(sysvar::rent::id(), false), ]; Ok(Instruction { @@ -524,8 +532,9 @@ pub fn initialize_multisig( } let data = TokenInstruction::InitializeMultisig { m }.pack()?; - let mut accounts = Vec::with_capacity(1 + signer_pubkeys.len()); + let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*multisig_pubkey, false)); + accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false)); for signer_pubkey in signer_pubkeys.iter() { accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); } diff --git a/program/src/processor.rs b/program/src/processor.rs index e4fe542..eb72297 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -16,6 +16,7 @@ use solana_sdk::{ info, program_error::{PrintProgramError, ProgramError}, pubkey::Pubkey, + sysvar::{rent::Rent, Sysvar}, }; use std::mem::size_of; @@ -31,6 +32,8 @@ impl Processor { ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let mint_info = next_account_info(account_info_iter)?; + let mint_info_data_len = mint_info.data_len(); + let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; let mut mint_info_data = mint_info.data.borrow_mut(); let mut mint: &mut Mint = state::unpack_unchecked(&mut mint_info_data)?; @@ -38,6 +41,10 @@ impl Processor { return Err(TokenError::AlreadyInUse.into()); } + if mint_info.lamports() < rent.minimum_balance(mint_info_data_len) { + return Err(TokenError::NotRentExempt.into()); + } + mint.mint_authority = COption::Some(mint_authority); mint.decimals = decimals; mint.is_initialized = true; @@ -52,6 +59,8 @@ impl Processor { let new_account_info = next_account_info(account_info_iter)?; let mint_info = next_account_info(account_info_iter)?; let owner_info = next_account_info(account_info_iter)?; + let new_account_info_data_len = new_account_info.data_len(); + let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; let mut new_account_data = new_account_info.data.borrow_mut(); let mut account: &mut Account = state::unpack_unchecked(&mut new_account_data)?; @@ -59,6 +68,10 @@ impl Processor { return Err(TokenError::AlreadyInUse.into()); } + if new_account_info.lamports() < rent.minimum_balance(new_account_info_data_len) { + return Err(TokenError::NotRentExempt.into()); + } + account.mint = *mint_info.key; account.owner = *owner_info.key; account.delegate = COption::None; @@ -79,12 +92,19 @@ impl Processor { pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let multisig_info = next_account_info(account_info_iter)?; + let multisig_info_data_len = multisig_info.data_len(); + let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; + let mut multisig_account_data = multisig_info.data.borrow_mut(); let mut multisig: &mut Multisig = state::unpack_unchecked(&mut multisig_account_data)?; if multisig.is_initialized { return Err(TokenError::AlreadyInUse.into()); } + if multisig_info.lamports() < rent.minimum_balance(multisig_info_data_len) { + return Err(TokenError::NotRentExempt.into()); + } + let signer_infos = account_info_iter.as_slice(); multisig.m = m; multisig.n = signer_infos.len() as u8; @@ -607,6 +627,9 @@ impl PrintProgramError for TokenError { E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, { match self { + TokenError::NotRentExempt => { + info!("Error: Lamport balance below rent-exempt threshold") + } TokenError::InsufficientFunds => info!("Error: insufficient funds"), TokenError::MintMismatch => info!("Error: Account not associated with this Mint"), TokenError::OwnerMismatch => info!("Error: owner does not match"), @@ -650,7 +673,7 @@ mod tests { }; use solana_sdk::{ account::Account as SolanaAccount, account_info::create_is_signer_account_infos, - clock::Epoch, instruction::Instruction, + clock::Epoch, instruction::Instruction, sysvar::rent, }; fn pubkey_rand() -> Pubkey { @@ -676,6 +699,22 @@ mod tests { TokenError::MintMismatch.into() } + fn rent_sysvar() -> SolanaAccount { + rent::create_account(42, &Rent::default()) + } + + fn mint_minimum_balance() -> u64 { + Rent::default().minimum_balance(size_of::()) + } + + fn account_minimum_balance() -> u64 { + Rent::default().minimum_balance(size_of::()) + } + + fn multisig_minimum_balance() -> u64 { + Rent::default().minimum_balance(size_of::()) + } + #[test] fn test_print_error() { let error = return_token_error_as_program_error(); @@ -683,7 +722,7 @@ mod tests { } #[test] - #[should_panic(expected = "Custom(1)")] + #[should_panic(expected = "Custom(2)")] fn test_error_unwrap() { Err::<(), ProgramError>(return_token_error_as_program_error()).unwrap(); } @@ -703,14 +742,27 @@ mod tests { let program_id = pubkey_rand(); let owner_key = pubkey_rand(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = SolanaAccount::new(42, size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // mint is not rent exempt + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar] + ) + ); + + mint_account.lamports = mint_minimum_balance(); // create new mint do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); @@ -719,14 +771,14 @@ mod tests { Err(TokenError::AlreadyInUse.into()), do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account] + vec![&mut mint_account, &mut rent_sysvar] ) ); // create another mint that can freeze do_process_instruction( initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account], + vec![&mut mint2_account, &mut rent_sysvar], ) .unwrap(); let mint2: &mut Mint = state::unpack(&mut mint2_account.data).unwrap(); @@ -737,16 +789,38 @@ mod tests { fn test_initialize_mint_account() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // account is not rent exempt + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar + ], + ) + ); + + account_account.lamports = account_minimum_balance(); // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); @@ -755,7 +829,12 @@ mod tests { Err(TokenError::AlreadyInUse.into()), do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar + ], ) ); } @@ -764,42 +843,64 @@ mod tests { fn test_transfer() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account3_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); let mismatch_key = pubkey_rand(); - let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mismatch_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); // create another account do_process_instruction( initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); // create another account do_process_instruction( initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account, &mut owner_account], + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); @@ -810,6 +911,7 @@ mod tests { &mut mismatch_account, &mut mint2_account, &mut owner_account, + &mut rent_sysvar, ], ) .unwrap(); @@ -817,7 +919,7 @@ mod tests { // create new mint & mint to account do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); do_process_instruction( @@ -1132,16 +1234,24 @@ mod tests { fn test_mintable_token_with_zero_supply() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut owner_account, &mut mint_account], + vec![ + &mut account_account, + &mut owner_account, + &mut mint_account, + &mut rent_sysvar, + ], ) .unwrap(); @@ -1149,7 +1259,7 @@ mod tests { let decimals = 2; do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); @@ -1179,9 +1289,11 @@ mod tests { fn test_approve() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); let owner_key = pubkey_rand(); @@ -1189,26 +1301,38 @@ mod tests { let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut owner_account, &mut mint_account], + vec![ + &mut account_account, + &mut owner_account, + &mut mint_account, + &mut rent_sysvar, + ], ) .unwrap(); // create another account do_process_instruction( initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut owner_account, &mut mint_account], + vec![ + &mut account2_account, + &mut owner_account, + &mut mint_account, + &mut rent_sysvar, + ], ) .unwrap(); // create new mint & mint to account do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut account_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); do_process_instruction( @@ -1292,18 +1416,23 @@ mod tests { fn test_set_authority() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let owner3_key = pubkey_rand(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // invalid account assert_eq!( @@ -1325,7 +1454,12 @@ mod tests { // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); @@ -1336,6 +1470,7 @@ mod tests { &mut account2_account, &mut mint2_account, &mut owner_account, + &mut rent_sysvar, ], ) .unwrap(); @@ -1455,7 +1590,7 @@ mod tests { // create new mint with owner do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); @@ -1559,7 +1694,7 @@ mod tests { // create mint with owner and freeze_authority do_process_instruction( initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account], + vec![&mut mint2_account, &mut rent_sysvar], ) .unwrap(); @@ -1614,42 +1749,65 @@ mod tests { fn test_mint_to() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account3_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let mismatch_key = pubkey_rand(); - let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mismatch_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let uninitialized_key = pubkey_rand(); - let mut uninitialized_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut uninitialized_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); // create another account do_process_instruction( initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); // create another account do_process_instruction( initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account, &mut owner_account], + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); @@ -1660,6 +1818,7 @@ mod tests { &mut mismatch_account, &mut mint2_account, &mut owner_account, + &mut rent_sysvar, ], ) .unwrap(); @@ -1667,7 +1826,7 @@ mod tests { // create new mint with owner do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); @@ -1764,42 +1923,64 @@ mod tests { fn test_burn() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account3_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); let mismatch_key = pubkey_rand(); - let mut mismatch_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mismatch_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); // create another account do_process_instruction( initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); // create another account do_process_instruction( initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account, &mut owner_account], + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); @@ -1810,6 +1991,7 @@ mod tests { &mut mismatch_account, &mut mint2_account, &mut owner_account, + &mut rent_sysvar, ], ) .unwrap(); @@ -1817,7 +1999,7 @@ mod tests { // create new mint do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); do_process_instruction( @@ -1920,21 +2102,44 @@ mod tests { fn test_multisig() { let program_id = pubkey_rand(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let account_key = pubkey_rand(); - let mut account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let multisig_key = pubkey_rand(); - let mut multisig_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut multisig_account = SolanaAccount::new(42, size_of::(), &program_id); let multisig_delegate_key = pubkey_rand(); - let mut multisig_delegate_account = - SolanaAccount::new(0, size_of::(), &program_id); + let mut multisig_delegate_account = SolanaAccount::new( + multisig_minimum_balance(), + size_of::(), + &program_id, + ); let signer_keys = vec![pubkey_rand(); MAX_SIGNERS]; let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().map(|key| key).collect(); let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; + let mut rent_sysvar = rent_sysvar(); + + // multisig is not rent exempt + let account_info_iter = &mut signer_accounts.iter_mut(); + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account, + &mut rent_sysvar, + &mut account_info_iter.next().unwrap(), + ], + ) + ); + + multisig_account.lamports = multisig_minimum_balance(); // single signer let account_info_iter = &mut signer_accounts.iter_mut(); @@ -1942,6 +2147,7 @@ mod tests { initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), vec![ &mut multisig_account, + &mut rent_sysvar, &mut account_info_iter.next().unwrap(), ], ) @@ -1959,6 +2165,7 @@ mod tests { .unwrap(), vec![ &mut multisig_delegate_account, + &mut rent_sysvar, &mut account_info_iter.next().unwrap(), &mut account_info_iter.next().unwrap(), &mut account_info_iter.next().unwrap(), @@ -1977,7 +2184,12 @@ mod tests { // create account with multisig owner do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), - vec![&mut account, &mut mint_account, &mut multisig_account], + vec![ + &mut account, + &mut mint_account, + &mut multisig_account, + &mut rent_sysvar, + ], ) .unwrap(); @@ -1994,6 +2206,7 @@ mod tests { &mut account2_account, &mut mint_account, &mut multisig_account, + &mut rent_sysvar, ], ) .unwrap(); @@ -2001,7 +2214,7 @@ mod tests { // create new mint with multisig owner do_process_instruction( initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); let account_info_iter = &mut signer_accounts.iter_mut(); @@ -2168,15 +2381,18 @@ mod tests { // freeze account let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account3_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); do_process_instruction( initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(), vec![ &mut account3_account, &mut mint2_account, &mut owner_account, + &mut rent_sysvar, ], ) .unwrap(); @@ -2189,7 +2405,7 @@ mod tests { 2, ) .unwrap(), - vec![&mut mint2_account], + vec![&mut mint2_account, &mut rent_sysvar], ) .unwrap(); let account_info_iter = &mut signer_accounts.iter_mut(); @@ -2399,17 +2615,22 @@ mod tests { fn test_close_account() { let program_id = pubkey_rand(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(2, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(2, size_of::(), &program_id); + let mut account3_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); + let mut rent_sysvar = rent_sysvar(); // uninitialized assert_eq!( @@ -2427,17 +2648,27 @@ mod tests { // initialize and mint to non-native account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], + vec![ + &mut mint_account, + &mut account_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); @@ -2452,12 +2683,17 @@ mod tests { &owner_key, ) .unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); assert!(account.is_native); - assert_eq!(account.amount, 2); + assert_eq!(account.amount, account_minimum_balance()); // close non-native account with balance assert_eq!( @@ -2471,7 +2707,7 @@ mod tests { ], ) ); - assert_eq!(account_account.lamports, 42); + assert_eq!(account_account.lamports, account_minimum_balance()); // empty account do_process_instruction( @@ -2506,16 +2742,23 @@ mod tests { let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap(); assert_eq!(account_account.lamports, 0); assert_eq!(account.amount, 0); - assert_eq!(account3_account.lamports, 44); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); // fund and initialize new non-native account to test close authority let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner2_key = pubkey_rand(); - let mut owner2_account = SolanaAccount::new(42, size_of::(), &program_id); + let mut owner2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); account_account.lamports = 2; @@ -2559,7 +2802,7 @@ mod tests { .unwrap(); assert_eq!(account_account.lamports, 0); assert_eq!(account.amount, 0); - assert_eq!(account3_account.lamports, 46); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); // close native account do_process_instruction( @@ -2575,21 +2818,25 @@ mod tests { assert!(account.is_native); assert_eq!(account_account.lamports, 0); assert_eq!(account.amount, 0); - assert_eq!(account3_account.lamports, 48); + assert_eq!(account3_account.lamports, 3 * account_minimum_balance() + 2); } #[test] fn test_native_token() { let program_id = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(2, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account3_key = pubkey_rand(); - let mut account3_account = SolanaAccount::new(2, 0, &program_id); + let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); + let mut rent_sysvar = rent_sysvar(); // initialize native account do_process_instruction( @@ -2600,12 +2847,17 @@ mod tests { &owner_key, ) .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert!(account.is_native); - assert_eq!(account.amount, 42); + assert_eq!(account.amount, account_minimum_balance()); // initialize native account do_process_instruction( @@ -2616,12 +2868,17 @@ mod tests { &owner_key, ) .unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); assert!(account.is_native); - assert_eq!(account.amount, 2); + assert_eq!(account.amount, account_minimum_balance()); // mint_to unsupported assert_eq!( @@ -2670,12 +2927,12 @@ mod tests { let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert!(account.is_native); - assert_eq!(account_account.lamports, 2); - assert_eq!(account.amount, 2); + assert_eq!(account_account.lamports, account_minimum_balance() - 40); + assert_eq!(account.amount, account_minimum_balance() - 40); let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); assert!(account.is_native); - assert_eq!(account2_account.lamports, 42); - assert_eq!(account.amount, 42); + assert_eq!(account2_account.lamports, account_minimum_balance() + 40); + assert_eq!(account.amount, account_minimum_balance() + 40); // close native account do_process_instruction( @@ -2691,16 +2948,21 @@ mod tests { assert!(account.is_native); assert_eq!(account_account.lamports, 0); assert_eq!(account.amount, 0); - assert_eq!(account3_account.lamports, 4); + assert_eq!( + account3_account.lamports, + 2 * account_minimum_balance() - 40 + ); } #[test] fn test_overflow() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); @@ -2708,12 +2970,19 @@ mod tests { let mint_owner_key = pubkey_rand(); let mut mint_owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // create victim account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); @@ -2724,6 +2993,7 @@ mod tests { &mut account2_account, &mut mint_account, &mut owner2_account, + &mut rent_sysvar, ], ) .unwrap(); @@ -2731,7 +3001,7 @@ mod tests { // create new mint with owner do_process_instruction( initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); @@ -2847,32 +3117,46 @@ mod tests { fn test_frozen() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account2_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); // create another account do_process_instruction( initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut owner_account], + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], ) .unwrap(); // create new mint and fund first account do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); do_process_instruction( @@ -2961,7 +3245,7 @@ mod tests { Err(TokenError::AccountFrozen.into()), do_process_instruction( revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account,], + vec![&mut account_account, &mut owner_account], ) ); @@ -3006,7 +3290,8 @@ mod tests { fn test_freeze_account() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut account_account = + SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account_owner_key = pubkey_rand(); let mut account_owner_account = SolanaAccount::default(); let owner_key = pubkey_rand(); @@ -3014,7 +3299,9 @@ mod tests { let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + let mut rent_sysvar = rent_sysvar(); // create account do_process_instruction( @@ -3023,6 +3310,7 @@ mod tests { &mut account_account, &mut mint_account, &mut account_owner_account, + &mut rent_sysvar, ], ) .unwrap(); @@ -3030,7 +3318,7 @@ mod tests { // create new mint with owner different from account owner do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], + vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); do_process_instruction( From 9e5f22223ca07ce5037c67be5669bfab3106f8ea Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 00:50:38 -0600 Subject: [PATCH 033/335] Add Account.rent_exempt_reserve --- program/src/processor.rs | 29 +++++++++++++++++------------ program/src/state.rs | 3 +++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index eb72297..fe9ce1e 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -41,7 +41,7 @@ impl Processor { return Err(TokenError::AlreadyInUse.into()); } - if mint_info.lamports() < rent.minimum_balance(mint_info_data_len) { + if !rent.is_exempt(mint_info.lamports(), mint_info_data_len) { return Err(TokenError::NotRentExempt.into()); } @@ -68,7 +68,7 @@ impl Processor { return Err(TokenError::AlreadyInUse.into()); } - if new_account_info.lamports() < rent.minimum_balance(new_account_info_data_len) { + if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) { return Err(TokenError::NotRentExempt.into()); } @@ -80,6 +80,7 @@ impl Processor { if *mint_info.key == crate::native_mint::id() { account.is_native = true; account.amount = new_account_info.lamports(); + account.rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); } else { account.is_native = false; account.amount = 0; @@ -101,7 +102,7 @@ impl Processor { return Err(TokenError::AlreadyInUse.into()); } - if multisig_info.lamports() < rent.minimum_balance(multisig_info_data_len) { + if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) { return Err(TokenError::NotRentExempt.into()); } @@ -183,6 +184,10 @@ impl Processor { .ok_or(TokenError::Overflow)?; if source_account.is_native { + // Ensure that wrapped SOL accounts remain rent-exempt + if source_account_info.lamports() < source_account.rent_exempt_reserve + amount { + return Err(TokenError::InsufficientFunds.into()); + } **source_account_info.lamports.borrow_mut() -= amount; **dest_account_info.lamports.borrow_mut() += amount; } @@ -2827,8 +2832,11 @@ mod tests { let mut mint_account = SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance() + 40, + size_of::(), + &program_id, + ); let account2_key = pubkey_rand(); let mut account2_account = SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); @@ -2857,7 +2865,7 @@ mod tests { .unwrap(); let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert!(account.is_native); - assert_eq!(account.amount, account_minimum_balance()); + assert_eq!(account.amount, account_minimum_balance() + 40); // initialize native account do_process_instruction( @@ -2927,8 +2935,8 @@ mod tests { let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert!(account.is_native); - assert_eq!(account_account.lamports, account_minimum_balance() - 40); - assert_eq!(account.amount, account_minimum_balance() - 40); + assert_eq!(account_account.lamports, account_minimum_balance()); + assert_eq!(account.amount, account_minimum_balance()); let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); assert!(account.is_native); assert_eq!(account2_account.lamports, account_minimum_balance() + 40); @@ -2948,10 +2956,7 @@ mod tests { assert!(account.is_native); assert_eq!(account_account.lamports, 0); assert_eq!(account.amount, 0); - assert_eq!( - account3_account.lamports, - 2 * account_minimum_balance() - 40 - ); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); } #[test] diff --git a/program/src/state.rs b/program/src/state.rs index 423fa64..f53bbca 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -46,6 +46,9 @@ pub struct Account { pub delegated_amount: u64, /// Optional authority to close the account. pub close_authority: COption, + /// An Account is required to be rent-exempt. This value logs the reserve required to be + /// rent-exempt so that wrapped SOL accounts do not drop below this threshold. + pub rent_exempt_reserve: u64, } impl Account { /// Checks if account is frozen From 00f3b2e5b51a0eff559d2d69771cba3f1cc67cb5 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 01:02:30 -0600 Subject: [PATCH 034/335] C headers --- program/inc/token.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/program/inc/token.h b/program/inc/token.h index 44f8423..b475b9c 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -118,6 +118,7 @@ typedef enum Token_TokenInstruction_Tag { * Accounts expected by this instruction: * * 0. `[writable]` The mint to initialize. + * 1. `[]` Rent sysvar * */ Token_TokenInstruction_InitializeMint, @@ -134,6 +135,7 @@ typedef enum Token_TokenInstruction_Tag { * 0. `[writable]` The account to initialize. * 1. `[]` The mint this account will be associated with. * 2. `[]` The new account's owner/multisignature. + * 3. `[]` Rent sysvar */ Token_TokenInstruction_InitializeAccount, /** @@ -150,7 +152,8 @@ typedef enum Token_TokenInstruction_Tag { * Accounts expected by this instruction: * * 0. `[writable]` The multisignature account to initialize. - * 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + * 2. `[]` Rent sysvar + * 3. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. */ Token_TokenInstruction_InitializeMultisig, /** @@ -441,6 +444,11 @@ typedef struct Token_Account { * Optional authority to close the account. */ Token_COption_Pubkey close_authority; + /** + * An Account is required to be rent-exempt. This value logs the reserve required to be + * rent-exempt so that wrapped SOL accounts do not drop below this threshold. + */ + uint64_t rent_exempt_reserve; } Token_Account; /** From f1103654703ef5195f6e4da5c34efe589304e473 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 01:20:49 -0600 Subject: [PATCH 035/335] Combine Account is_native and rent_exempt_reserve fields; wrapped SOL amount reflects only amoutn over rent_exempt_reserve --- program/src/processor.rs | 81 ++++++++++++++++++++++++++-------------- program/src/state.rs | 13 ++++--- 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index fe9ce1e..7c1302e 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -78,11 +78,11 @@ impl Processor { account.delegated_amount = 0; account.state = AccountState::Initialized; if *mint_info.key == crate::native_mint::id() { - account.is_native = true; - account.amount = new_account_info.lamports(); - account.rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); + let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); + account.is_native = COption::Some(rent_exempt_reserve); + account.amount = new_account_info.lamports() - rent_exempt_reserve; } else { - account.is_native = false; + account.is_native = COption::None; account.amount = 0; }; @@ -183,11 +183,7 @@ impl Processor { .checked_add(amount) .ok_or(TokenError::Overflow)?; - if source_account.is_native { - // Ensure that wrapped SOL accounts remain rent-exempt - if source_account_info.lamports() < source_account.rent_exempt_reserve + amount { - return Err(TokenError::InsufficientFunds.into()); - } + if source_account.is_native() { **source_account_info.lamports.borrow_mut() -= amount; **dest_account_info.lamports.borrow_mut() += amount; } @@ -362,7 +358,7 @@ impl Processor { return Err(TokenError::AccountFrozen.into()); } - if dest_account.is_native { + if dest_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } if mint_info.key != &dest_account.mint { @@ -407,7 +403,7 @@ impl Processor { let mut source_data = source_account_info.data.borrow_mut(); let source_account: &mut Account = state::unpack(&mut source_data)?; - if source_account.is_native { + if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } if source_account.amount < amount { @@ -457,7 +453,7 @@ impl Processor { let mut source_data = source_account_info.data.borrow_mut(); let source_account: &mut Account = state::unpack(&mut source_data)?; - if !source_account.is_native && source_account.amount != 0 { + if !source_account.is_native() && source_account.amount != 0 { return Err(TokenError::NonNativeHasBalance.into()); } @@ -493,7 +489,7 @@ impl Processor { let mut source_data = source_account_info.data.borrow_mut(); let source_account: &mut Account = state::unpack(&mut source_data)?; - if source_account.is_native { + if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } if mint_info.key != &source_account.mint { @@ -2626,8 +2622,11 @@ mod tests { let mut account_account = SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance() + 42, + size_of::(), + &program_id, + ); let account3_key = pubkey_rand(); let mut account3_account = SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); @@ -2697,8 +2696,8 @@ mod tests { ) .unwrap(); let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account.amount, account_minimum_balance()); + assert!(account.is_native()); + assert_eq!(account.amount, 42); // close non-native account with balance assert_eq!( @@ -2820,10 +2819,13 @@ mod tests { ) .unwrap(); let account: &mut Account = state::unpack_unchecked(&mut account2_account.data).unwrap(); - assert!(account.is_native); + assert!(account.is_native()); assert_eq!(account_account.lamports, 0); assert_eq!(account.amount, 0); - assert_eq!(account3_account.lamports, 3 * account_minimum_balance() + 2); + assert_eq!( + account3_account.lamports, + 3 * account_minimum_balance() + 2 + 42 + ); } #[test] @@ -2864,8 +2866,8 @@ mod tests { ) .unwrap(); let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account.amount, account_minimum_balance() + 40); + assert!(account.is_native()); + assert_eq!(account.amount, 40); // initialize native account do_process_instruction( @@ -2885,8 +2887,8 @@ mod tests { ) .unwrap(); let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native); - assert_eq!(account.amount, account_minimum_balance()); + assert!(account.is_native()); + assert_eq!(account.amount, 0); // mint_to unsupported assert_eq!( @@ -2914,7 +2916,28 @@ mod tests { ) ); - // initialize native account + // ensure can't transfer below rent-exempt reserve + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 50, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // transfer between native accounts do_process_instruction( transfer( &program_id, @@ -2934,13 +2957,13 @@ mod tests { .unwrap(); let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert!(account.is_native); + assert!(account.is_native()); assert_eq!(account_account.lamports, account_minimum_balance()); - assert_eq!(account.amount, account_minimum_balance()); + assert_eq!(account.amount, 0); let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native); + assert!(account.is_native()); assert_eq!(account2_account.lamports, account_minimum_balance() + 40); - assert_eq!(account.amount, account_minimum_balance() + 40); + assert_eq!(account.amount, 40); // close native account do_process_instruction( @@ -2953,7 +2976,7 @@ mod tests { ) .unwrap(); let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap(); - assert!(account.is_native); + assert!(account.is_native()); assert_eq!(account_account.lamports, 0); assert_eq!(account.amount, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); diff --git a/program/src/state.rs b/program/src/state.rs index f53bbca..7f920ef 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -40,21 +40,24 @@ pub struct Account { pub delegate: COption, /// The account's state pub state: AccountState, - /// Is this a native token - pub is_native: bool, + /// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account + /// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped + /// SOL accounts do not drop below this threshold. + pub is_native: COption, /// The amount delegated pub delegated_amount: u64, /// Optional authority to close the account. pub close_authority: COption, - /// An Account is required to be rent-exempt. This value logs the reserve required to be - /// rent-exempt so that wrapped SOL accounts do not drop below this threshold. - pub rent_exempt_reserve: u64, } impl Account { /// Checks if account is frozen pub fn is_frozen(&self) -> bool { self.state == AccountState::Frozen } + /// Checks if account is native + pub fn is_native(&self) -> bool { + self.is_native.is_some() + } } impl IsInitialized for Account { fn is_initialized(&self) -> bool { From 398194d5616e60c51a2bb58e4434844807f6d3f0 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 09:40:39 -0600 Subject: [PATCH 036/335] More C headers --- program/inc/token.h | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index b475b9c..ac8cc98 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -407,6 +407,31 @@ typedef struct Token_Mint { Token_COption_Pubkey freeze_authority; } Token_Mint; +/** + * A C representation of Rust's `std::option::Option` + */ +typedef enum Token_COption_u64_Tag { + /** + * No value + */ + Token_COption_u64_None_u64, + /** + * Some value `T` + */ + Token_COption_u64_Some_u64, +} Token_COption_u64_Tag; + +typedef struct Token_COption_u64_Token_Some_Body_u64 { + uint64_t _0; +} Token_COption_u64_Token_Some_Body_u64; + +typedef struct Token_COption_u64 { + Token_COption_u64_Tag tag; + union { + Token_COption_u64_Token_Some_Body_u64 some; + }; +} Token_COption_u64; + /** * Account data. */ @@ -433,9 +458,11 @@ typedef struct Token_Account { */ Token_AccountState state; /** - * Is this a native token + * If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account + * is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped + * SOL accounts do not drop below this threshold. */ - bool is_native; + Token_COption_u64 is_native; /** * The amount delegated */ @@ -444,11 +471,6 @@ typedef struct Token_Account { * Optional authority to close the account. */ Token_COption_Pubkey close_authority; - /** - * An Account is required to be rent-exempt. This value logs the reserve required to be - * rent-exempt so that wrapped SOL accounts do not drop below this threshold. - */ - uint64_t rent_exempt_reserve; } Token_Account; /** From 3ed23283adca0119435063f93d0ecd3248681b8f Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 13:06:23 -0600 Subject: [PATCH 037/335] Reinstate Mint supply (#342) * Reinstate Mint supply, and adjust with Minto & Burn * C headers * Patch token-cli * Patch token-swap --- program/inc/token.h | 18 ++-- program/src/instruction.rs | 18 ++-- program/src/processor.rs | 213 ++++++++++++++++++++++++++++--------- program/src/state.rs | 2 + 4 files changed, 187 insertions(+), 64 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index ac8cc98..a05c087 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -152,8 +152,8 @@ typedef enum Token_TokenInstruction_Tag { * Accounts expected by this instruction: * * 0. `[writable]` The multisignature account to initialize. - * 2. `[]` Rent sysvar - * 3. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + * 1. `[]` Rent sysvar + * 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. */ Token_TokenInstruction_InitializeMultisig, /** @@ -219,7 +219,7 @@ typedef enum Token_TokenInstruction_Tag { * * Multisignature authority * 0. `[writable]` The mint or account to change the authority of. * 1. `[]` The mint's or account's multisignature authority. - * 3. ..3+M '[signer]' M signer accounts + * 2. ..2+M '[signer]' M signer accounts */ Token_TokenInstruction_SetAuthority, /** @@ -247,12 +247,14 @@ typedef enum Token_TokenInstruction_Tag { * * * Single owner/delegate * 0. `[writable]` The account to burn from. - * 1. `[signer]` The account's owner/delegate. + * 1. '[writable]' The token mint. + * 2. `[signer]` The account's owner/delegate. * * * Multisignature owner/delegate * 0. `[writable]` The account to burn from. - * 1. `[]` The account's multisignature owner/delegate. - * 2. ..2+M '[signer]' M signer accounts. + * 1. '[writable]' The token mint. + * 2. `[]` The account's multisignature owner/delegate. + * 3. ..3+M '[signer]' M signer accounts. */ Token_TokenInstruction_Burn, /** @@ -393,6 +395,10 @@ typedef struct Token_Mint { * further tokens may be minted. */ Token_COption_Pubkey mint_authority; + /** + * Total supply of tokens. + */ + uint64_t supply; /** * Number of base 10 digits to the right of the decimal place. */ diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 79bd0a0..0165600 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -64,8 +64,8 @@ pub enum TokenInstruction { /// Accounts expected by this instruction: /// /// 0. `[writable]` The multisignature account to initialize. - /// 2. `[]` Rent sysvar - /// 3. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + /// 1. `[]` Rent sysvar + /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. InitializeMultisig { /// The number of signers (M) required to validate this multisignature account. m: u8, @@ -133,7 +133,7 @@ pub enum TokenInstruction { /// * Multisignature authority /// 0. `[writable]` The mint or account to change the authority of. /// 1. `[]` The mint's or account's multisignature authority. - /// 3. ..3+M '[signer]' M signer accounts + /// 2. ..2+M '[signer]' M signer accounts SetAuthority { /// The type of authority to update. authority_type: AuthorityType, @@ -165,12 +165,14 @@ pub enum TokenInstruction { /// /// * Single owner/delegate /// 0. `[writable]` The account to burn from. - /// 1. `[signer]` The account's owner/delegate. + /// 1. '[writable]' The token mint. + /// 2. `[signer]` The account's owner/delegate. /// /// * Multisignature owner/delegate /// 0. `[writable]` The account to burn from. - /// 1. `[]` The account's multisignature owner/delegate. - /// 2. ..2+M '[signer]' M signer accounts. + /// 1. '[writable]' The token mint. + /// 2. `[]` The account's multisignature owner/delegate. + /// 3. ..3+M '[signer]' M signer accounts. Burn { /// The amount of tokens to burn. amount: u64, @@ -696,14 +698,16 @@ pub fn mint_to( pub fn burn( token_program_id: &Pubkey, account_pubkey: &Pubkey, + mint_pubkey: &Pubkey, authority_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { let data = TokenInstruction::Burn { amount }.pack()?; - let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new(*mint_pubkey, false)); accounts.push(AccountMeta::new_readonly( *authority_pubkey, signer_pubkeys.is_empty(), diff --git a/program/src/processor.rs b/program/src/processor.rs index 7c1302e..15181e0 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -387,6 +387,11 @@ impl Processor { .checked_add(amount) .ok_or(TokenError::Overflow)?; + mint.supply = mint + .supply + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + Ok(()) } @@ -398,14 +403,21 @@ impl Processor { ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let source_account_info = next_account_info(account_info_iter)?; + let mint_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; + let mut mint_data = mint_info.data.borrow_mut(); + let mint: &mut Mint = state::unpack(&mut mint_data)?; + let mut source_data = source_account_info.data.borrow_mut(); let source_account: &mut Account = state::unpack(&mut source_data)?; if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } + if mint_info.key != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } if source_account.amount < amount { return Err(TokenError::InsufficientFunds.into()); } @@ -439,6 +451,7 @@ impl Processor { } source_account.amount -= amount; + mint.supply -= amount; Ok(()) } @@ -1268,6 +1281,7 @@ mod tests { *mint, Mint { mint_authority: COption::Some(owner_key), + supply: 0, decimals, is_initialized: true, freeze_authority: COption::None, @@ -1832,13 +1846,26 @@ mod tests { .unwrap(); // mint to + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + assert_eq!(mint.supply, 42); + let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(dest_account.amount, 42); + + // mint to another account to test supply accumulation do_process_instruction( mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), vec![&mut mint_account, &mut account2_account, &mut owner_account], ) .unwrap(); - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + assert_eq!(mint.supply, 84); let dest_account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); assert_eq!(dest_account.amount, 42); @@ -2010,13 +2037,18 @@ mod tests { .unwrap(); // missing signer - let mut instruction = burn(&program_id, &account_key, &delegate_key, &[], 42).unwrap(); + let mut instruction = + burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap(); instruction.accounts[1].is_signer = false; assert_eq!( Err(TokenError::OwnerMismatch.into()), do_process_instruction( instruction, - vec![&mut account_account, &mut delegate_account], + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], ) ); @@ -2024,19 +2056,29 @@ mod tests { assert_eq!( Err(TokenError::OwnerMismatch.into()), do_process_instruction( - burn(&program_id, &account_key, &owner2_key, &[], 42).unwrap(), - vec![&mut account_account, &mut owner2_account], + burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // mint mismatch + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(), + vec![&mut mismatch_account, &mut mint_account, &mut owner_account], ) ); // burn do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut account_account, &mut owner_account], + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + assert_eq!(mint.supply, 1000 - 42); let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert_eq!(account.amount, 1000 - 42); @@ -2044,8 +2086,16 @@ mod tests { assert_eq!( Err(TokenError::InsufficientFunds.into()), do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(), - vec![&mut account_account, &mut owner_account], + burn( + &program_id, + &account_key, + &mint_key, + &owner_key, + &[], + 100_000_000 + ) + .unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], ) ); @@ -2072,20 +2122,33 @@ mod tests { assert_eq!( Err(TokenError::InsufficientFunds.into()), do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 100_000_000).unwrap(), - vec![&mut account_account, &mut owner_account], + burn( + &program_id, + &account_key, + &mint_key, + &owner_key, + &[], + 100_000_000 + ) + .unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], ) ); // burn via delegate do_process_instruction( - burn(&program_id, &account_key, &delegate_key, &[], 84).unwrap(), - vec![&mut account_account, &mut delegate_account], + burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + ], ) .unwrap(); // match - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + assert_eq!(mint.supply, 1000 - 42 - 84); let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert_eq!(account.amount, 1000 - 42 - 84); @@ -2093,8 +2156,20 @@ mod tests { assert_eq!( Err(TokenError::OwnerMismatch.into()), do_process_instruction( - burn(&program_id, &account_key, &delegate_key, &[], 100).unwrap(), - vec![&mut account_account, &mut delegate_account], + burn( + &program_id, + &account_key, + &mint_key, + &delegate_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], ) ); } @@ -2338,6 +2413,7 @@ mod tests { burn( &program_id, &account_key, + &mint_key, &multisig_key, &[&signer_keys[0]], 42, @@ -2345,6 +2421,7 @@ mod tests { .unwrap(), vec![ &mut account, + &mut mint_account, &mut multisig_account, &mut account_info_iter.next().unwrap(), ], @@ -2357,6 +2434,7 @@ mod tests { burn( &program_id, &account_key, + &mint_key, &multisig_delegate_key, &signer_key_refs, 42, @@ -2364,6 +2442,7 @@ mod tests { .unwrap(), vec![ &mut account, + &mut mint_account, &mut multisig_delegate_account, &mut account_info_iter.next().unwrap(), &mut account_info_iter.next().unwrap(), @@ -2715,8 +2794,8 @@ mod tests { // empty account do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut account_account, &mut owner_account], + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); @@ -2908,11 +2987,32 @@ mod tests { ); // burn unsupported + let bogus_mint_key = pubkey_rand(); + let mut bogus_mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + do_process_instruction( + initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(), + vec![&mut bogus_mint_account, &mut rent_sysvar], + ) + .unwrap(); + assert_eq!( Err(TokenError::NativeNotSupported.into()), do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut account_account, &mut owner_account], + burn( + &program_id, + &account_key, + &bogus_mint_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![ + &mut account_account, + &mut bogus_mint_account, + &mut owner_account + ], ) ); @@ -3002,7 +3102,7 @@ mod tests { SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); - // create victim account + // create an account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), vec![ @@ -3033,28 +3133,7 @@ mod tests { ) .unwrap(); - // mint the max to attacker - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &mint_owner_key, - &[], - 42, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint the max to victum + // mint the max to an account do_process_instruction( mint_to( &program_id, @@ -3075,7 +3154,7 @@ mod tests { let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX); - // mint one more + // attempt to mint one more to account assert_eq!( Err(TokenError::Overflow.into()), do_process_instruction( @@ -3095,10 +3174,39 @@ mod tests { ], ) ); + let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); - // mint back to large amount + // atttempt to mint one more to the other account + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &mint_owner_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut mint_owner_account, + ], + ) + ); + + // burn some of the supply + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - account.amount = 0; + assert_eq!(account.amount, u64::MAX - 100); + do_process_instruction( mint_to( &program_id, @@ -3106,7 +3214,7 @@ mod tests { &account_key, &mint_owner_key, &[], - u64::MAX, + 100, ) .unwrap(), vec![ @@ -3119,7 +3227,10 @@ mod tests { let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX); - // transfer to burn victim + // manipulate account balance to attempt overflow transfer + let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); + account.amount = 1; + assert_eq!( Err(TokenError::Overflow.into()), do_process_instruction( @@ -3308,8 +3419,8 @@ mod tests { assert_eq!( Err(TokenError::AccountFrozen.into()), do_process_instruction( - burn(&program_id, &account_key, &owner_key, &[], 100).unwrap(), - vec![&mut account_account, &mut owner_account,], + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], ) ); } diff --git a/program/src/state.rs b/program/src/state.rs index 7f920ef..5b3981c 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -12,6 +12,8 @@ pub struct Mint { /// mint creation. If no mint authority is present then the mint has a fixed supply and no /// further tokens may be minted. pub mint_authority: COption, + /// Total supply of tokens. + pub supply: u64, /// Number of base 10 digits to the right of the decimal place. pub decimals: u8, /// Is `true` if this structure has been initialized From bdbd484decd4a09a5148dbc4b6557adcd023648a Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 14:31:59 -0600 Subject: [PATCH 038/335] Use checked math everywhere (#346) --- program/src/processor.rs | 47 ++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 15181e0..e6dacf0 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -80,7 +80,10 @@ impl Processor { if *mint_info.key == crate::native_mint::id() { let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); account.is_native = COption::Some(rent_exempt_reserve); - account.amount = new_account_info.lamports() - rent_exempt_reserve; + account.amount = new_account_info + .lamports() + .checked_sub(rent_exempt_reserve) + .ok_or(TokenError::Overflow)?; } else { account.is_native = COption::None; account.amount = 0; @@ -164,7 +167,10 @@ impl Processor { if source_account.delegated_amount < amount { return Err(TokenError::InsufficientFunds.into()); } - source_account.delegated_amount -= amount; + source_account.delegated_amount = source_account + .delegated_amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; if source_account.delegated_amount == 0 { source_account.delegate = COption::None; } @@ -177,15 +183,25 @@ impl Processor { )?, }; - source_account.amount -= amount; + source_account.amount = source_account + .amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; dest_account.amount = dest_account .amount .checked_add(amount) .ok_or(TokenError::Overflow)?; if source_account.is_native() { - **source_account_info.lamports.borrow_mut() -= amount; - **dest_account_info.lamports.borrow_mut() += amount; + let source_starting_lamports = source_account_info.lamports(); + **source_account_info.lamports.borrow_mut() = source_starting_lamports + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + + let dest_starting_lamports = dest_account_info.lamports(); + **dest_account_info.lamports.borrow_mut() = dest_starting_lamports + .checked_add(amount) + .ok_or(TokenError::Overflow)?; } Ok(()) @@ -437,7 +453,10 @@ impl Processor { if source_account.delegated_amount < amount { return Err(TokenError::InsufficientFunds.into()); } - source_account.delegated_amount -= amount; + source_account.delegated_amount = source_account + .delegated_amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; if source_account.delegated_amount == 0 { source_account.delegate = COption::None; } @@ -450,8 +469,14 @@ impl Processor { )?, } - source_account.amount -= amount; - mint.supply -= amount; + source_account.amount = source_account + .amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + mint.supply = mint + .supply + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; Ok(()) } @@ -480,7 +505,11 @@ impl Processor { account_info_iter.as_slice(), )?; - **dest_account_info.lamports.borrow_mut() += source_account_info.lamports(); + let dest_starting_lamports = dest_account_info.lamports(); + **dest_account_info.lamports.borrow_mut() = dest_starting_lamports + .checked_add(source_account_info.lamports()) + .ok_or(TokenError::Overflow)?; + **source_account_info.lamports.borrow_mut() = 0; source_account.amount = 0; From 10df5eb9abd268b2967a3c943e8cc5b324806b9e Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 15:22:03 -0600 Subject: [PATCH 039/335] Require valid Mint for InitializeAccount --- program/src/error.rs | 3 + program/src/instruction.rs | 6 +- program/src/processor.rs | 255 +++++++++++++++++++++---------------- 3 files changed, 155 insertions(+), 109 deletions(-) diff --git a/program/src/error.rs b/program/src/error.rs index 4a9e223..904dc21 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -13,6 +13,9 @@ pub enum TokenError { /// Insufficient funds for the operation requested. #[error("Insufficient funds")] InsufficientFunds, + /// Invalid Mint. + #[error("Invalid Mint")] + InvalidMint, /// Account not associated with this Mint. #[error("Account not associated with this Mint")] MintMismatch, diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 0165600..701f4bc 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -37,8 +37,10 @@ pub enum TokenInstruction { /// The freeze authority/multisignature of the mint. freeze_authority: COption, }, - /// Initializes a new account to hold tokens. If this account is associated with the native mint - /// then the token balance of the initialized account will be equal to the amount of SOL in the account. + /// Initializes a new account to hold tokens. If this account is associated with the native + /// mint then the token balance of the initialized account will be equal to the amount of SOL + /// in the account. If this account is associated with another mint, that mint must be + /// initialized before this command can succeed. /// /// The `InitializeAccount` instruction requires no signers and MUST be included within /// the same Transaction as the system program's `CreateInstruction` that creates the account diff --git a/program/src/processor.rs b/program/src/processor.rs index e6dacf0..ae39050 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -72,6 +72,12 @@ impl Processor { return Err(TokenError::NotRentExempt.into()); } + if *mint_info.key != crate::native_mint::id() { + let mut mint_info_data = mint_info.data.borrow_mut(); + let _: &mut Mint = state::unpack(&mut mint_info_data) + .map_err(|_| Into::::into(TokenError::InvalidMint))?; + } + account.mint = *mint_info.key; account.owner = *owner_info.key; account.delegate = COption::None; @@ -674,6 +680,7 @@ impl PrintProgramError for TokenError { info!("Error: Lamport balance below rent-exempt threshold") } TokenError::InsufficientFunds => info!("Error: insufficient funds"), + TokenError::InvalidMint => info!("Error: Invalid Mint"), TokenError::MintMismatch => info!("Error: Account not associated with this Mint"), TokenError::OwnerMismatch => info!("Error: owner does not match"), TokenError::FixedSupply => info!("Error: the total supply of this token is fixed"), @@ -765,7 +772,7 @@ mod tests { } #[test] - #[should_panic(expected = "Custom(2)")] + #[should_panic(expected = "Custom(3)")] fn test_error_unwrap() { Err::<(), ProgramError>(return_token_error_as_program_error()).unwrap(); } @@ -836,7 +843,8 @@ mod tests { let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(0, size_of::(), &program_id); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); // account is not rent exempt @@ -855,6 +863,27 @@ mod tests { account_account.lamports = account_minimum_balance(); + // mint is not valid (not initialized) + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar + ], + ) + ); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), @@ -907,10 +936,15 @@ mod tests { let mut mint_account = SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), @@ -949,22 +983,19 @@ mod tests { // create mismatch account do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), vec![ &mut mismatch_account, - &mut mint2_account, + &mut mint_account, &mut owner_account, &mut rent_sysvar, ], ) .unwrap(); + let account: &mut Account = state::unpack(&mut mismatch_account.data).unwrap(); + account.mint = mint2_key; - // create new mint & mint to account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); + // mint to account do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], @@ -1286,18 +1317,6 @@ mod tests { SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut owner_account, - &mut mint_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - // create mint-able token with zero supply let decimals = 2; do_process_instruction( @@ -1317,6 +1336,18 @@ mod tests { } ); + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + // mint to do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), @@ -1349,13 +1380,20 @@ mod tests { SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), vec![ &mut account_account, - &mut owner_account, &mut mint_account, + &mut owner_account, &mut rent_sysvar, ], ) @@ -1366,19 +1404,14 @@ mod tests { initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), vec![ &mut account2_account, - &mut owner_account, &mut mint_account, + &mut owner_account, &mut rent_sysvar, ], ) .unwrap(); - // create new mint & mint to account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); + // mint to account do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], @@ -1478,6 +1511,20 @@ mod tests { SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create mint with owner and freeze_authority + do_process_instruction( + initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account, &mut rent_sysvar], + ) + .unwrap(); + // invalid account assert_eq!( Err(TokenError::UninitializedState.into()), @@ -1631,13 +1678,6 @@ mod tests { ) .unwrap(); - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - // wrong owner assert_eq!( Err(TokenError::OwnerMismatch.into()), @@ -1735,13 +1775,6 @@ mod tests { ) ); - // create mint with owner and freeze_authority - do_process_instruction( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - // set freeze_authority do_process_instruction( set_authority( @@ -1812,13 +1845,18 @@ mod tests { let mut mint_account = SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let uninitialized_key = pubkey_rand(); let mut uninitialized_account = SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), @@ -1857,22 +1895,17 @@ mod tests { // create mismatch account do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), vec![ &mut mismatch_account, - &mut mint2_account, + &mut mint_account, &mut owner_account, &mut rent_sysvar, ], ) .unwrap(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); + let account: &mut Account = state::unpack(&mut mismatch_account.data).unwrap(); + account.mint = mint2_key; // mint to do_process_instruction( @@ -2001,10 +2034,15 @@ mod tests { let mut mint_account = SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mint2_key = pubkey_rand(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), @@ -2043,22 +2081,19 @@ mod tests { // create mismatch account do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint2_key, &owner_key).unwrap(), + initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), vec![ &mut mismatch_account, - &mut mint2_account, + &mut mint_account, &mut owner_account, &mut rent_sysvar, ], ) .unwrap(); + let account: &mut Account = state::unpack(&mut mismatch_account.data).unwrap(); + account.mint = mint2_key; - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); + // mint to account do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], @@ -2286,6 +2321,13 @@ mod tests { ) .unwrap(); + // create new mint with multisig owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create account with multisig owner do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), @@ -2316,12 +2358,7 @@ mod tests { ) .unwrap(); - // create new mint with multisig owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); + // mint to account let account_info_iter = &mut signer_accounts.iter_mut(); do_process_instruction( mint_to( @@ -2495,16 +2532,6 @@ mod tests { let mint2_key = pubkey_rand(); let mut mint2_account = SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint2_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); do_process_instruction( initialize_mint( &program_id, @@ -2517,6 +2544,16 @@ mod tests { vec![&mut mint2_account, &mut rent_sysvar], ) .unwrap(); + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint2_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); let account_info_iter = &mut signer_accounts.iter_mut(); do_process_instruction( mint_to( @@ -2758,6 +2795,11 @@ mod tests { ); // initialize and mint to non-native account + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), vec![ @@ -2768,11 +2810,6 @@ mod tests { ], ) .unwrap(); - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), vec![ @@ -3131,6 +3168,13 @@ mod tests { SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create an account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), @@ -3155,13 +3199,6 @@ mod tests { ) .unwrap(); - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - // mint the max to an account do_process_instruction( mint_to( @@ -3297,6 +3334,13 @@ mod tests { SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); + // create new mint and fund first account + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), @@ -3321,12 +3365,7 @@ mod tests { ) .unwrap(); - // create new mint and fund first account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); + // fund first account do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], @@ -3471,6 +3510,13 @@ mod tests { SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); let mut rent_sysvar = rent_sysvar(); + // create new mint with owner different from account owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &account_owner_key).unwrap(), @@ -3483,12 +3529,7 @@ mod tests { ) .unwrap(); - // create new mint with owner different from account owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); + // mint to account do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], From 718cb1756cc475ad06425d843cdc2b7546e07ffb Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 15:22:37 -0600 Subject: [PATCH 040/335] C headers doc --- program/inc/token.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index a05c087..a3da9eb 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -123,8 +123,10 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_InitializeMint, /** - * Initializes a new account to hold tokens. If this account is associated with the native mint - * then the token balance of the initialized account will be equal to the amount of SOL in the account. + * Initializes a new account to hold tokens. If this account is associated with the native + * mint then the token balance of the initialized account will be equal to the amount of SOL + * in the account. If this account is associated with another mint, that mint must be + * initialized before this command can succeed. * * The `InitializeAccount` instruction requires no signers and MUST be included within * the same Transaction as the system program's `CreateInstruction` that creates the account From 84c8391282eb14c0e08e97b21fa821d502af652c Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 27 Aug 2020 11:12:49 -0700 Subject: [PATCH 041/335] Add Transfer2/Approve2/MintTo2/Burn2 instructions for improved hardware wallet support --- program/src/error.rs | 3 + program/src/instruction.rs | 385 ++++++++++++++++++++++++++++++++++++- program/src/processor.rs | 273 ++++++++++++++++++++++++-- 3 files changed, 647 insertions(+), 14 deletions(-) diff --git a/program/src/error.rs b/program/src/error.rs index 904dc21..a69e57e 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -61,6 +61,9 @@ pub enum TokenError { /// Account is frozen; all account operations will fail #[error("Account is frozen")] AccountFrozen, + /// Mint decimals mismatch between the client and mint + #[error("The provided decimals value different from the Mint decimals")] + MintDecimalsMismatch, } impl From for ProgramError { fn from(e: TokenError) -> Self { diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 701f4bc..1d21ce7 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -94,7 +94,7 @@ pub enum TokenInstruction { }, /// Approves a delegate. A delegate is given the authority over /// tokens on behalf of the source account's owner. - + /// /// Accounts expected by this instruction: /// /// * Single owner @@ -225,6 +225,109 @@ pub enum TokenInstruction { /// 2. `[]` The mint's multisignature freeze authority. /// 3. ..3+M '[signer]' M signer accounts. ThawAccount, + + /// Transfers tokens from one account to another either directly or via a delegate. If this + /// account is associated with the native mint then equal amounts of SOL and Tokens will be + /// transferred to the destination account. + /// + /// This instruction differs from Transfer in that the token mint and decimals value is + /// asserted by the caller. This may be useful when creating transactions offline or within a + /// hardware wallet. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The source account. + /// 1. '[]' The token mint. + /// 2. `[writable]` The destination account. + /// 3. '[signer]' The source account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The source account. + /// 1. '[]' The token mint. + /// 2. `[writable]` The destination account. + /// 3. '[]' The source account's multisignature owner/delegate. + /// 4. ..4+M '[signer]' M signer accounts. + Transfer2 { + /// The amount of tokens to transfer. + amount: u64, + /// Expected number of base 10 digits to the right of the decimal place. + decimals: u8, + }, + /// Approves a delegate. A delegate is given the authority over + /// tokens on behalf of the source account's owner. + /// + /// This instruction differs from Approve in that the token mint and decimals value is asserted + /// by the caller. This may be useful when creating transactions offline or within a hardware + /// wallet. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The source account. + /// 1. '[]' The token mint. + /// 2. `[]` The delegate. + /// 3. `[signer]` The source account owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The source account. + /// 1. '[]' The token mint. + /// 2. `[]` The delegate. + /// 3. '[]' The source account's multisignature owner. + /// 4. ..4+M '[signer]' M signer accounts + Approve2 { + /// The amount of tokens the delegate is approved for. + amount: u64, + /// Expected number of base 10 digits to the right of the decimal place. + decimals: u8, + }, + /// Mints new tokens to an account. The native mint does not support minting. + /// + /// This instruction differs from MintTo in that the decimals value is asserted by the + /// caller. This may be useful when creating transactions offline or within a hardware wallet. + /// + /// Accounts expected by this instruction: + /// + /// * Single authority + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[signer]` The mint's minting authority. + /// + /// * Multisignature authority + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[]` The mint's multisignature mint-tokens authority. + /// 3. ..3+M '[signer]' M signer accounts. + MintTo2 { + /// The amount of new tokens to mint. + amount: u64, + /// Expected number of base 10 digits to the right of the decimal place. + decimals: u8, + }, + /// Burns tokens by removing them from an account. `Burn2` does not support accounts + /// associated with the native mint, use `CloseAccount` instead. + /// + /// This instruction differs from Burn in that the decimals value is asserted by the caller. + /// This may be useful when creating transactions offline or within a hardware wallet. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. '[writable]' The token mint. + /// 2. `[signer]` The account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. '[writable]' The token mint. + /// 2. `[]` The account's multisignature owner/delegate. + /// 3. ..3+M '[signer]' M signer accounts. + Burn2 { + /// The amount of tokens to burn. + amount: u64, + /// Expected number of base 10 digits to the right of the decimal place. + decimals: u8, + }, } impl TokenInstruction { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). @@ -323,6 +426,67 @@ impl TokenInstruction { 9 => Self::CloseAccount, 10 => Self::FreezeAccount, 11 => Self::ThawAccount, + 12 => { + if input.len() < size_of::() + size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + let mut input_len = 0; + input_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) }; + input_len += size_of::(); + + let decimals = unsafe { *(&input[input_len] as *const u8) }; + + Self::Transfer2 { amount, decimals } + } + 13 => { + if input.len() < size_of::() + size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + let mut input_len = 0; + input_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) }; + input_len += size_of::(); + + let decimals = unsafe { *(&input[input_len] as *const u8) }; + + Self::Approve2 { amount, decimals } + } + 14 => { + if input.len() < size_of::() + size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + let mut input_len = 0; + input_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) }; + input_len += size_of::(); + + let decimals = unsafe { *(&input[input_len] as *const u8) }; + + Self::MintTo2 { amount, decimals } + } + 15 => { + if input.len() < size_of::() + size_of::() + size_of::() { + return Err(TokenError::InvalidInstruction.into()); + } + let mut input_len = 0; + input_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) }; + input_len += size_of::(); + + let decimals = unsafe { *(&input[input_len] as *const u8) }; + + Self::Burn2 { amount, decimals } + } + _ => return Err(TokenError::InvalidInstruction.into()), }) } @@ -428,6 +592,59 @@ impl TokenInstruction { output[output_len] = 11; output_len += size_of::(); } + Self::Transfer2 { amount, decimals } => { + output[output_len] = 12; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; + *value = *amount; + output_len += size_of::(); + + let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; + *value = *decimals; + output_len += size_of::(); + } + Self::Approve2 { amount, decimals } => { + output[output_len] = 13; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; + *value = *amount; + output_len += size_of::(); + + let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; + *value = *decimals; + output_len += size_of::(); + } + Self::MintTo2 { amount, decimals } => { + output[output_len] = 14; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; + *value = *amount; + output_len += size_of::(); + + let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; + *value = *decimals; + output_len += size_of::(); + } + + Self::Burn2 { amount, decimals } => { + output[output_len] = 15; + output_len += size_of::(); + + #[allow(clippy::cast_ptr_alignment)] + let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; + *value = *amount; + output_len += size_of::(); + + let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; + *value = *decimals; + output_len += size_of::(); + } } output.truncate(output_len); @@ -809,6 +1026,132 @@ pub fn thaw_account( }) } +/// Creates a `Transfer2` instruction. +#[allow(clippy::too_many_arguments)] +pub fn transfer2( + token_program_id: &Pubkey, + source_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + destination_pubkey: &Pubkey, + authority_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, + decimals: u8, +) -> Result { + let data = TokenInstruction::Transfer2 { amount, decimals }.pack()?; + + let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*source_pubkey, false)); + accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); + accounts.push(AccountMeta::new(*destination_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *authority_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates an `Approve2` instruction. +#[allow(clippy::too_many_arguments)] +pub fn approve2( + token_program_id: &Pubkey, + source_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + delegate_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, + decimals: u8, +) -> Result { + let data = TokenInstruction::Approve2 { amount, decimals }.pack()?; + + let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*source_pubkey, false)); + accounts.push(AccountMeta::new_readonly(*mint_pubkey, false)); + accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `MintTo2` instruction. +pub fn mint_to2( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, + account_pubkey: &Pubkey, + owner_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, + decimals: u8, +) -> Result { + let data = TokenInstruction::MintTo2 { amount, decimals }.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*mint_pubkey, false)); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *owner_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + +/// Creates a `Burn2` instruction. +pub fn burn2( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + authority_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + amount: u64, + decimals: u8, +) -> Result { + let data = TokenInstruction::Burn2 { amount, decimals }.pack()?; + + let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*account_pubkey, false)); + accounts.push(AccountMeta::new(*mint_pubkey, false)); + accounts.push(AccountMeta::new_readonly( + *authority_pubkey, + signer_pubkeys.is_empty(), + )); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new(**signer_pubkey, true)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + /// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS pub fn is_valid_signer_index(index: usize) -> bool { !(index < MIN_SIGNERS || index > MAX_SIGNERS) @@ -928,5 +1271,45 @@ mod test { assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); + + let check = TokenInstruction::Transfer2 { + amount: 1, + decimals: 2, + }; + let packed = check.pack().unwrap(); + let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Approve2 { + amount: 1, + decimals: 2, + }; + let packed = check.pack().unwrap(); + let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::MintTo2 { + amount: 1, + decimals: 2, + }; + let packed = check.pack().unwrap(); + let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::Burn2 { + amount: 1, + decimals: 2, + }; + let packed = check.pack().unwrap(); + let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); } } diff --git a/program/src/processor.rs b/program/src/processor.rs index ae39050..4826f2a 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -137,9 +137,18 @@ impl Processor { program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, + expected_decimals: Option, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + + let expected_mint_info = if let Some(expected_decimals) = expected_decimals { + Some((next_account_info(account_info_iter)?, expected_decimals)) + } else { + None + }; + let dest_account_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; @@ -162,6 +171,19 @@ impl Processor { return Err(TokenError::AccountFrozen.into()); } + if let Some((mint_account_info, expected_decimals)) = expected_mint_info { + if source_account.mint != *mint_account_info.key { + return Err(TokenError::MintMismatch.into()); + } + + let mut mint_info_data = mint_account_info.data.borrow_mut(); + let mint: &Mint = state::unpack_unchecked(&mut mint_info_data)?; + + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + match source_account.delegate { COption::Some(ref delegate) if authority_info.key == delegate => { Self::validate_owner( @@ -218,19 +240,39 @@ impl Processor { program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, + expected_decimals: Option, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; + let expected_mint_info = if let Some(expected_decimals) = expected_decimals { + Some((next_account_info(account_info_iter)?, expected_decimals)) + } else { + None + }; + let delegate_info = next_account_info(account_info_iter)?; + let owner_info = next_account_info(account_info_iter)?; let mut source_data = source_account_info.data.borrow_mut(); let mut source_account: &mut Account = state::unpack(&mut source_data)?; - let delegate_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } + if let Some((mint_account_info, expected_decimals)) = expected_mint_info { + if source_account.mint != *mint_account_info.key { + return Err(TokenError::MintMismatch.into()); + } + + let mut mint_info_data = mint_account_info.data.borrow_mut(); + let mint: &Mint = state::unpack_unchecked(&mut mint_info_data)?; + + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + Self::validate_owner( program_id, &source_account.owner, @@ -367,6 +409,7 @@ impl Processor { program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, + expected_decimals: Option, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let mint_info = next_account_info(account_info_iter)?; @@ -390,6 +433,12 @@ impl Processor { let mut mint_info_data = mint_info.data.borrow_mut(); let mint: &mut Mint = state::unpack(&mut mint_info_data)?; + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + match mint.mint_authority { COption::Some(mint_authority) => { Self::validate_owner( @@ -422,8 +471,10 @@ impl Processor { program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, + expected_decimals: Option, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); + let source_account_info = next_account_info(account_info_iter)?; let mint_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; @@ -447,6 +498,12 @@ impl Processor { return Err(TokenError::AccountFrozen.into()); } + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + match source_account.delegate { COption::Some(ref delegate) if authority_info.key == delegate => { Self::validate_owner( @@ -596,11 +653,11 @@ impl Processor { } TokenInstruction::Transfer { amount } => { info!("Instruction: Transfer"); - Self::process_transfer(program_id, accounts, amount) + Self::process_transfer(program_id, accounts, amount, None) } TokenInstruction::Approve { amount } => { info!("Instruction: Approve"); - Self::process_approve(program_id, accounts, amount) + Self::process_approve(program_id, accounts, amount, None) } TokenInstruction::Revoke => { info!("Instruction: Revoke"); @@ -615,11 +672,11 @@ impl Processor { } TokenInstruction::MintTo { amount } => { info!("Instruction: MintTo"); - Self::process_mint_to(program_id, accounts, amount) + Self::process_mint_to(program_id, accounts, amount, None) } TokenInstruction::Burn { amount } => { info!("Instruction: Burn"); - Self::process_burn(program_id, accounts, amount) + Self::process_burn(program_id, accounts, amount, None) } TokenInstruction::CloseAccount => { info!("Instruction: CloseAccount"); @@ -633,6 +690,22 @@ impl Processor { info!("Instruction: FreezeAccount"); Self::process_toggle_freeze_account(program_id, accounts, false) } + TokenInstruction::Transfer2 { amount, decimals } => { + info!("Instruction: Transfer"); + Self::process_transfer(program_id, accounts, amount, Some(decimals)) + } + TokenInstruction::Approve2 { amount, decimals } => { + info!("Instruction: Approve"); + Self::process_approve(program_id, accounts, amount, Some(decimals)) + } + TokenInstruction::MintTo2 { amount, decimals } => { + info!("Instruction: MintTo"); + Self::process_mint_to(program_id, accounts, amount, Some(decimals)) + } + TokenInstruction::Burn2 { amount, decimals } => { + info!("Instruction: Burn"); + Self::process_burn(program_id, accounts, amount, Some(decimals)) + } } } @@ -706,6 +779,9 @@ impl PrintProgramError for TokenError { } TokenError::MintCannotFreeze => info!("Error: This token mint cannot freeze accounts"), TokenError::AccountFrozen => info!("Error: Account is frozen"), + TokenError::MintDecimalsMismatch => { + info!("Error: decimals different from the Mint decimals") + } } } } @@ -717,10 +793,7 @@ solana_sdk::program_stubs!(); #[cfg(test)] mod tests { use super::*; - use crate::instruction::{ - approve, burn, close_account, freeze_account, initialize_account, initialize_mint, - initialize_multisig, mint_to, revoke, set_authority, thaw_account, transfer, MAX_SIGNERS, - }; + use crate::instruction::*; use solana_sdk::{ account::Account as SolanaAccount, account_info::create_is_signer_account_infos, clock::Epoch, instruction::Instruction, sysvar::rent, @@ -1118,19 +1191,69 @@ mod tests { ) .unwrap(); - // transfer rest + // incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + transfer2( + &program_id, + &account2_key, + &mint_key, + &account_key, + &owner_key, + &[], + 1, + 10 // <-- incorrect decimals + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut account_account, + &mut owner_account, + ], + ) + ); + + // incorrect mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + transfer2( + &program_id, + &account2_key, + &account3_key, // <-- incorrect mint + &account_key, + &owner_key, + &[], + 1, + 2 + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account3_account, // <-- incorrect mint + &mut account_account, + &mut owner_account, + ], + ) + ); + // transfer rest with explicit decimals do_process_instruction( - transfer( + transfer2( &program_id, &account2_key, + &mint_key, &account_key, &owner_key, &[], 500, + 2, ) .unwrap(), vec![ &mut account2_account, + &mut mint_account, &mut account_account, &mut owner_account, ], @@ -1355,9 +1478,47 @@ mod tests { ) .unwrap(); + // mint to 2, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + mint_to2( + &program_id, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + decimals + 1 + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); assert_eq!(dest_account.amount, 42); + + // mint to 2 + do_process_instruction( + mint_to2( + &program_id, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + decimals, + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); + let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); + assert_eq!(dest_account.amount, 84); } #[test] @@ -1481,6 +1642,76 @@ mod tests { ) .unwrap(); + // approve delegate 2, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + approve2( + &program_id, + &account_key, + &mint_key, + &delegate_key, + &owner_key, + &[], + 100, + 0 // <-- incorrect decimals + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // approve delegate 2, with incorrect mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + approve2( + &program_id, + &account_key, + &account2_key, // <-- bad mint + &delegate_key, + &owner_key, + &[], + 100, + 0 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, // <-- bad mint + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // approve delegate 2 + do_process_instruction( + approve2( + &program_id, + &account_key, + &mint_key, + &delegate_key, + &owner_key, + &[], + 100, + 2, + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + // revoke delegate do_process_instruction( revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), @@ -2136,7 +2367,23 @@ mod tests { // burn do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 21).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // burn2, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + burn2(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // burn2 + do_process_instruction( + burn2(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); From b0da9e1eefc50c1edd425aafc8abdaac14e72ec4 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 27 Aug 2020 16:34:50 -0700 Subject: [PATCH 042/335] Adjust native mint --- program/src/native_mint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs index e502128..622199c 100644 --- a/program/src/native_mint.rs +++ b/program/src/native_mint.rs @@ -4,7 +4,7 @@ pub const DECIMALS: u8 = 9; // The Mint for native SOL Token accounts -solana_sdk::declare_id!("So12111111111111111111111111111111111111111"); +solana_sdk::declare_id!("So11111111111111111111111111111111111111112"); #[cfg(test)] mod tests { From 4d41bccd28de55cf2550c4b276c3a3d3648683d7 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 27 Aug 2020 12:20:36 -0700 Subject: [PATCH 043/335] Update token.h --- program/inc/token.h | 139 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/program/inc/token.h b/program/inc/token.h index a3da9eb..32df44b 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -180,6 +180,7 @@ typedef enum Token_TokenInstruction_Tag { /** * Approves a delegate. A delegate is given the authority over * tokens on behalf of the source account's owner. + * * Accounts expected by this instruction: * * * Single owner @@ -311,6 +312,96 @@ typedef enum Token_TokenInstruction_Tag { * 3. ..3+M '[signer]' M signer accounts. */ Token_TokenInstruction_ThawAccount, + /** + * Transfers tokens from one account to another either directly or via a delegate. If this + * account is associated with the native mint then equal amounts of SOL and Tokens will be + * transferred to the destination account. + * + * This instruction differs from Transfer in that the token mint and decimals value is + * asserted by the caller. This may be useful when creating transactions offline or within a + * hardware wallet. + * + * Accounts expected by this instruction: + * + * * Single owner/delegate + * 0. `[writable]` The source account. + * 1. '[]' The token mint. + * 2. `[writable]` The destination account. + * 3. '[signer]' The source account's owner/delegate. + * + * * Multisignature owner/delegate + * 0. `[writable]` The source account. + * 1. '[]' The token mint. + * 2. `[writable]` The destination account. + * 3. '[]' The source account's multisignature owner/delegate. + * 4. ..4+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_Transfer2, + /** + * Approves a delegate. A delegate is given the authority over + * tokens on behalf of the source account's owner. + * + * This instruction differs from Approve in that the token mint and decimals value is asserted + * by the caller. This may be useful when creating transactions offline or within a hardware + * wallet. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The source account. + * 1. '[]' The token mint. + * 2. `[]` The delegate. + * 3. `[signer]` The source account owner. + * + * * Multisignature owner + * 0. `[writable]` The source account. + * 1. '[]' The token mint. + * 2. `[]` The delegate. + * 3. '[]' The source account's multisignature owner. + * 4. ..4+M '[signer]' M signer accounts + */ + Token_TokenInstruction_Approve2, + /** + * Mints new tokens to an account. The native mint does not support minting. + * + * This instruction differs from MintTo in that the decimals value is asserted by the + * caller. This may be useful when creating transactions offline or within a hardware wallet. + * + * Accounts expected by this instruction: + * + * * Single authority + * 0. `[writable]` The mint. + * 1. `[writable]` The account to mint tokens to. + * 2. `[signer]` The mint's minting authority. + * + * * Multisignature authority + * 0. `[writable]` The mint. + * 1. `[writable]` The account to mint tokens to. + * 2. `[]` The mint's multisignature mint-tokens authority. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_MintTo2, + /** + * Burns tokens by removing them from an account. `Burn2` does not support accounts + * associated with the native mint, use `CloseAccount` instead. + * + * This instruction differs from Burn in that the decimals value is asserted by the caller. + * This may be useful when creating transactions offline or within a hardware wallet. + * + * Accounts expected by this instruction: + * + * * Single owner/delegate + * 0. `[writable]` The account to burn from. + * 1. '[writable]' The token mint. + * 2. `[signer]` The account's owner/delegate. + * + * * Multisignature owner/delegate + * 0. `[writable]` The account to burn from. + * 1. '[writable]' The token mint. + * 2. `[]` The account's multisignature owner/delegate. + * 3. ..3+M '[signer]' M signer accounts. + */ + Token_TokenInstruction_Burn2, } Token_TokenInstruction_Tag; typedef struct Token_TokenInstruction_Token_InitializeMint_Body { @@ -374,6 +465,50 @@ typedef struct Token_TokenInstruction_Token_Burn_Body { uint64_t amount; } Token_TokenInstruction_Token_Burn_Body; +typedef struct Token_TokenInstruction_Token_Transfer2_Body { + /** + * The amount of tokens to transfer. + */ + uint64_t amount; + /** + * Expected number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_Transfer2_Body; + +typedef struct Token_TokenInstruction_Token_Approve2_Body { + /** + * The amount of tokens the delegate is approved for. + */ + uint64_t amount; + /** + * Expected number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_Approve2_Body; + +typedef struct Token_TokenInstruction_Token_MintTo2_Body { + /** + * The amount of new tokens to mint. + */ + uint64_t amount; + /** + * Expected number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_MintTo2_Body; + +typedef struct Token_TokenInstruction_Token_Burn2_Body { + /** + * The amount of tokens to burn. + */ + uint64_t amount; + /** + * Expected number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_Burn2_Body; + typedef struct Token_TokenInstruction { Token_TokenInstruction_Tag tag; union { @@ -384,6 +519,10 @@ typedef struct Token_TokenInstruction { Token_TokenInstruction_Token_SetAuthority_Body set_authority; Token_TokenInstruction_Token_MintTo_Body mint_to; Token_TokenInstruction_Token_Burn_Body burn; + Token_TokenInstruction_Token_Transfer2_Body transfer2; + Token_TokenInstruction_Token_Approve2_Body approve2; + Token_TokenInstruction_Token_MintTo2_Body mint_to2; + Token_TokenInstruction_Token_Burn2_Body burn2; }; } Token_TokenInstruction; From 1916d1d61d4ca34a2c1ac7b406cf6887685e76af Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 27 Aug 2020 19:41:14 -0600 Subject: [PATCH 044/335] New spl-token v1.1 program id (#348) --- program/program-id.md | 2 +- program/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/program/program-id.md b/program/program-id.md index 0e3c586..6f7f354 100644 --- a/program/program-id.md +++ b/program/program-id.md @@ -1 +1 @@ -TokensVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o +TokenFSDHBLHfbT65SnYJx77ysXc1WTC2W3kvnXnZZR diff --git a/program/src/lib.rs b/program/src/lib.rs index c6096a5..e188755 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -25,4 +25,4 @@ pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { amount as f64 / 10_usize.pow(decimals as u32) as f64 } -solana_sdk::declare_id!("TokensVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"); +solana_sdk::declare_id!("TokenFSDHBLHfbT65SnYJx77ysXc1WTC2W3kvnXnZZR"); From fe85b19606d9b42b34d6c5f6b263c6902bf6872c Mon Sep 17 00:00:00 2001 From: Jack May Date: Thu, 27 Aug 2020 21:19:15 -0700 Subject: [PATCH 045/335] Safer pack/unpack (#349) * Safer pack/unpack * fix cli * clippy * fix swap * nit * clippy Co-authored-by: Michael Vines --- program/Cargo.toml | 2 + program/src/instruction.rs | 447 +++++--------- program/src/lib.rs | 1 + program/src/option.rs | 109 ---- program/src/pack.rs | 76 +++ program/src/processor.rs | 1201 ++++++++++++++++++++---------------- program/src/state.rs | 199 +++++- 7 files changed, 1101 insertions(+), 934 deletions(-) create mode 100644 program/src/pack.rs diff --git a/program/Cargo.toml b/program/Cargo.toml index e112088..2c8c9ca 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -23,6 +23,8 @@ num-traits = "0.2" remove_dir_all = "=0.5.0" solana-sdk = { version = "1.3.4", default-features = false, optional = true } thiserror = "1.0" +arrayref = "0.3.6" +num_enum = "0.5.1" [dev-dependencies] rand = { version = "0.7.0"} diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 1d21ce7..8e1a045 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -7,6 +7,7 @@ use solana_sdk::{ pubkey::Pubkey, sysvar, }; +use std::convert::TryInto; use std::mem::size_of; /// Minimum number of multisignature signers (min N) @@ -332,29 +333,14 @@ pub enum TokenInstruction { impl TokenInstruction { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). pub fn unpack(input: &[u8]) -> Result { - if input.len() < size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - Ok(match input[0] { - 0 => { - if input.len() < size_of::() + size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - let mut input_len = 0; - input_len += size_of::(); - - let decimals = unsafe { *(&input[input_len] as *const u8) }; - input_len += size_of::(); - - let mint_authority = unsafe { *(&input[input_len] as *const u8 as *const Pubkey) }; - input_len += size_of::(); - - let freeze_authority = COption::unpack_or( - input, - &mut input_len, - Into::::into(TokenError::InvalidInstruction), - )?; + use TokenError::InvalidInstruction; + let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?; + Ok(match tag { + 0 => { + let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?; + let (mint_authority, rest) = Self::unpack_pubkey(rest)?; + let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?; Self::InitializeMint { mint_authority, freeze_authority, @@ -363,126 +349,80 @@ impl TokenInstruction { } 1 => Self::InitializeAccount, 2 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let m = unsafe { *(&input[1] as *const u8) }; + let &m = rest.get(0).ok_or(InvalidInstruction)?; Self::InitializeMultisig { m } } - 3 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - Self::Transfer { amount } - } - 4 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); + 3 | 4 | 7 | 8 => { + let amount = rest + .get(..8) + .and_then(|slice| slice.try_into().ok()) + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + match tag { + 3 => Self::Transfer { amount }, + 4 => Self::Approve { amount }, + 7 => Self::MintTo { amount }, + 8 => Self::Burn { amount }, + _ => unreachable!(), } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - Self::Approve { amount } } 5 => Self::Revoke, 6 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - let mut input_len = 0; - input_len += size_of::(); - let authority_type = AuthorityType::from(input[1])?; - input_len += size_of::(); - - let new_authority = COption::unpack_or( - input, - &mut input_len, - Into::::into(TokenError::InvalidInstruction), - )?; + let (authority_type, rest) = rest + .split_first() + .ok_or_else(|| ProgramError::from(InvalidInstruction)) + .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?; + let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?; Self::SetAuthority { authority_type, new_authority, } } - 7 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - Self::MintTo { amount } - } - 8 => { - if input.len() < size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[size_of::()] as *const u8 as *const u64) }; - Self::Burn { amount } - } 9 => Self::CloseAccount, 10 => Self::FreezeAccount, 11 => Self::ThawAccount, 12 => { - if input.len() < size_of::() + size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - let mut input_len = 0; - input_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) }; - input_len += size_of::(); - - let decimals = unsafe { *(&input[input_len] as *const u8) }; + let (amount, rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; Self::Transfer2 { amount, decimals } } 13 => { - if input.len() < size_of::() + size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - let mut input_len = 0; - input_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) }; - input_len += size_of::(); - - let decimals = unsafe { *(&input[input_len] as *const u8) }; + let (amount, rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; Self::Approve2 { amount, decimals } } 14 => { - if input.len() < size_of::() + size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - let mut input_len = 0; - input_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) }; - input_len += size_of::(); - - let decimals = unsafe { *(&input[input_len] as *const u8) }; + let (amount, rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; Self::MintTo2 { amount, decimals } } 15 => { - if input.len() < size_of::() + size_of::() + size_of::() { - return Err(TokenError::InvalidInstruction.into()); - } - let mut input_len = 0; - input_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let amount = unsafe { *(&input[input_len] as *const u8 as *const u64) }; - input_len += size_of::(); - - let decimals = unsafe { *(&input[input_len] as *const u8) }; + let (amount, rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; Self::Burn2 { amount, decimals } } @@ -492,163 +432,106 @@ impl TokenInstruction { } /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. - pub fn pack(&self) -> Result, ProgramError> { - let mut output = vec![0u8; size_of::()]; - let mut output_len = 0; + pub fn pack(&self) -> Vec { + let mut buf = Vec::with_capacity(size_of::()); match self { - Self::InitializeMint { - mint_authority, - freeze_authority, + &Self::InitializeMint { + ref mint_authority, + ref freeze_authority, decimals, } => { - output[output_len] = 0; - output_len += size_of::(); - - let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; - *value = *decimals; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut Pubkey) }; - *value = *mint_authority; - output_len += size_of::(); - - freeze_authority.pack(&mut output, &mut output_len); + buf.push(0); + buf.push(decimals); + buf.extend_from_slice(mint_authority.as_ref()); + Self::pack_pubkey_option(freeze_authority, &mut buf); } - Self::InitializeAccount => { - output[output_len] = 1; - output_len += size_of::(); + Self::InitializeAccount => buf.push(1), + &Self::InitializeMultisig { m } => { + buf.push(2); + buf.push(m); } - Self::InitializeMultisig { m } => { - output[output_len] = 2; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u8) }; - *value = *m; - output_len += size_of::(); + &Self::Transfer { amount } => { + buf.push(3); + buf.extend_from_slice(&amount.to_le_bytes()); } - Self::Transfer { amount } => { - output[output_len] = 3; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); + &Self::Approve { amount } => { + buf.push(4); + buf.extend_from_slice(&amount.to_le_bytes()); } - Self::Approve { amount } => { - output[output_len] = 4; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); + &Self::MintTo { amount } => { + buf.push(7); + buf.extend_from_slice(&amount.to_le_bytes()); } - Self::Revoke => { - output[output_len] = 5; - output_len += size_of::(); + &Self::Burn { amount } => { + buf.push(8); + buf.extend_from_slice(&amount.to_le_bytes()); } + Self::Revoke => buf.push(5), Self::SetAuthority { authority_type, - new_authority, + ref new_authority, } => { - output[output_len] = 6; - output_len += size_of::(); - - output[output_len] = authority_type.into(); - output_len += size_of::(); - - new_authority.pack(&mut output, &mut output_len); - } - Self::MintTo { amount } => { - output[output_len] = 7; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - } - Self::Burn { amount } => { - output[output_len] = 8; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); + buf.push(6); + buf.push(authority_type.into()); + Self::pack_pubkey_option(new_authority, &mut buf); } - Self::CloseAccount => { - output[output_len] = 9; - output_len += size_of::(); + Self::CloseAccount => buf.push(9), + Self::FreezeAccount => buf.push(10), + Self::ThawAccount => buf.push(11), + &Self::Transfer2 { amount, decimals } => { + buf.push(12); + buf.extend_from_slice(&amount.to_le_bytes()); + buf.push(decimals); } - Self::FreezeAccount => { - output[output_len] = 10; - output_len += size_of::(); + &Self::Approve2 { amount, decimals } => { + buf.push(13); + buf.extend_from_slice(&amount.to_le_bytes()); + buf.push(decimals); } - Self::ThawAccount => { - output[output_len] = 11; - output_len += size_of::(); + &Self::MintTo2 { amount, decimals } => { + buf.push(14); + buf.extend_from_slice(&amount.to_le_bytes()); + buf.push(decimals); } - Self::Transfer2 { amount, decimals } => { - output[output_len] = 12; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - - let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; - *value = *decimals; - output_len += size_of::(); + &Self::Burn2 { amount, decimals } => { + buf.push(15); + buf.extend_from_slice(&amount.to_le_bytes()); + buf.push(decimals); } - Self::Approve2 { amount, decimals } => { - output[output_len] = 13; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - - let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; - *value = *decimals; - output_len += size_of::(); - } - Self::MintTo2 { amount, decimals } => { - output[output_len] = 14; - output_len += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); - - let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; - *value = *decimals; - output_len += size_of::(); - } - - Self::Burn2 { amount, decimals } => { - output[output_len] = 15; - output_len += size_of::(); + }; + buf + } - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[output_len] as *mut u8 as *mut u64) }; - *value = *amount; - output_len += size_of::(); + fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> { + if input.len() >= 32 { + let (key, rest) = input.split_at(32); + let pk = Pubkey::new(key); + Ok((pk, rest)) + } else { + Err(TokenError::InvalidInstruction.into()) + } + } - let value = unsafe { &mut *(&mut output[output_len] as *mut u8) }; - *value = *decimals; - output_len += size_of::(); + fn unpack_pubkey_option(input: &[u8]) -> Result<(COption, &[u8]), ProgramError> { + match input.split_first() { + Option::Some((&0, rest)) => Ok((COption::None, rest)), + Option::Some((&1, rest)) if rest.len() >= 32 => { + let (key, rest) = rest.split_at(32); + let pk = Pubkey::new(key); + Ok((COption::Some(pk), rest)) } + _ => Err(TokenError::InvalidInstruction.into()), } + } - output.truncate(output_len); - Ok(output) + fn pack_pubkey_option(value: &COption, buf: &mut Vec) { + match *value { + COption::Some(ref key) => { + buf.push(1); + buf.extend_from_slice(&key.to_bytes()); + } + COption::None => buf.push(0), + } } } @@ -701,7 +584,7 @@ pub fn initialize_mint( freeze_authority, decimals, } - .pack()?; + .pack(); let accounts = vec![ AccountMeta::new(*mint_pubkey, false), @@ -722,7 +605,7 @@ pub fn initialize_account( mint_pubkey: &Pubkey, owner_pubkey: &Pubkey, ) -> Result { - let data = TokenInstruction::InitializeAccount.pack()?; + let data = TokenInstruction::InitializeAccount.pack(); // TODO do we need to return result? let accounts = vec![ AccountMeta::new(*account_pubkey, false), @@ -751,7 +634,7 @@ pub fn initialize_multisig( { return Err(ProgramError::MissingRequiredSignature); } - let data = TokenInstruction::InitializeMultisig { m }.pack()?; + let data = TokenInstruction::InitializeMultisig { m }.pack(); let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*multisig_pubkey, false)); @@ -776,7 +659,7 @@ pub fn transfer( signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { - let data = TokenInstruction::Transfer { amount }.pack()?; + let data = TokenInstruction::Transfer { amount }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*source_pubkey, false)); @@ -805,7 +688,7 @@ pub fn approve( signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { - let data = TokenInstruction::Approve { amount }.pack()?; + let data = TokenInstruction::Approve { amount }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*source_pubkey, false)); @@ -832,7 +715,7 @@ pub fn revoke( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { - let data = TokenInstruction::Revoke.pack()?; + let data = TokenInstruction::Revoke.pack(); let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); accounts.push(AccountMeta::new_readonly(*source_pubkey, false)); @@ -865,7 +748,7 @@ pub fn set_authority( authority_type, new_authority, } - .pack()?; + .pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*owned_pubkey, false)); @@ -893,7 +776,7 @@ pub fn mint_to( signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { - let data = TokenInstruction::MintTo { amount }.pack()?; + let data = TokenInstruction::MintTo { amount }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*mint_pubkey, false)); @@ -922,7 +805,7 @@ pub fn burn( signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { - let data = TokenInstruction::Burn { amount }.pack()?; + let data = TokenInstruction::Burn { amount }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*account_pubkey, false)); @@ -950,7 +833,7 @@ pub fn close_account( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { - let data = TokenInstruction::CloseAccount.pack()?; + let data = TokenInstruction::CloseAccount.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*account_pubkey, false)); @@ -978,7 +861,7 @@ pub fn freeze_account( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { - let data = TokenInstruction::FreezeAccount.pack()?; + let data = TokenInstruction::FreezeAccount.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*account_pubkey, false)); @@ -1006,7 +889,7 @@ pub fn thaw_account( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { - let data = TokenInstruction::ThawAccount.pack()?; + let data = TokenInstruction::ThawAccount.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*account_pubkey, false)); @@ -1038,7 +921,7 @@ pub fn transfer2( amount: u64, decimals: u8, ) -> Result { - let data = TokenInstruction::Transfer2 { amount, decimals }.pack()?; + let data = TokenInstruction::Transfer2 { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*source_pubkey, false)); @@ -1071,7 +954,7 @@ pub fn approve2( amount: u64, decimals: u8, ) -> Result { - let data = TokenInstruction::Approve2 { amount, decimals }.pack()?; + let data = TokenInstruction::Approve2 { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*source_pubkey, false)); @@ -1102,7 +985,7 @@ pub fn mint_to2( amount: u64, decimals: u8, ) -> Result { - let data = TokenInstruction::MintTo2 { amount, decimals }.pack()?; + let data = TokenInstruction::MintTo2 { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*mint_pubkey, false)); @@ -1132,7 +1015,7 @@ pub fn burn2( amount: u64, decimals: u8, ) -> Result { - let data = TokenInstruction::Burn2 { amount, decimals }.pack()?; + let data = TokenInstruction::Burn2 { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*account_pubkey, false)); @@ -1168,7 +1051,7 @@ mod test { mint_authority: Pubkey::new(&[1u8; 32]), freeze_authority: COption::None, }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let mut expect = Vec::from([0u8, 2]); expect.extend_from_slice(&[1u8; 32]); expect.extend_from_slice(&[0]); @@ -1181,7 +1064,7 @@ mod test { mint_authority: Pubkey::new(&[2u8; 32]), freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let mut expect = vec![0u8, 2]; expect.extend_from_slice(&[2u8; 32]); expect.extend_from_slice(&[1]); @@ -1191,35 +1074,35 @@ mod test { assert_eq!(unpacked, check); let check = TokenInstruction::InitializeAccount; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([1u8]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::InitializeMultisig { m: 1 }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([2u8, 1]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::Transfer { amount: 1 }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::Approve { amount: 1 }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::Revoke; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([5u8]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); @@ -1229,7 +1112,7 @@ mod test { authority_type: AuthorityType::FreezeAccount, new_authority: COption::Some(Pubkey::new(&[4u8; 32])), }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let mut expect = Vec::from([6u8, 1]); expect.extend_from_slice(&[1]); expect.extend_from_slice(&[4u8; 32]); @@ -1238,35 +1121,35 @@ mod test { assert_eq!(unpacked, check); let check = TokenInstruction::MintTo { amount: 1 }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::Burn { amount: 1 }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::CloseAccount; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([9u8]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::FreezeAccount; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([10u8]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); let check = TokenInstruction::ThawAccount; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([11u8]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); @@ -1276,7 +1159,7 @@ mod test { amount: 1, decimals: 2, }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); @@ -1286,7 +1169,7 @@ mod test { amount: 1, decimals: 2, }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); @@ -1296,7 +1179,7 @@ mod test { amount: 1, decimals: 2, }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); @@ -1306,7 +1189,7 @@ mod test { amount: 1, decimals: 2, }; - let packed = check.pack().unwrap(); + let packed = check.pack(); let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]); assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); diff --git a/program/src/lib.rs b/program/src/lib.rs index e188755..cb58c52 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -7,6 +7,7 @@ pub mod error; pub mod instruction; pub mod native_mint; pub mod option; +pub mod pack; pub mod processor; pub mod state; diff --git a/program/src/option.rs b/program/src/option.rs index 9e6f16d..677408b 100644 --- a/program/src/option.rs +++ b/program/src/option.rs @@ -676,55 +676,6 @@ impl COption { pub fn replace(&mut self, value: T) -> COption { mem::replace(self, COption::Some(value)) } - - ///////////////////////////////////////////////////////////////////////// - // SPL Token-Specific Methods - ///////////////////////////////////////////////////////////////////////// - - /// Packs a COption into a mutable slice as compactly as possible - #[inline] - pub fn pack(&self, output: &mut [u8], cursor: &mut usize) - where - T: Copy, - { - match self { - COption::Some(some_value) => { - output[*cursor] = 1; - *cursor += mem::size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let value = unsafe { &mut *(&mut output[*cursor] as *mut u8 as *mut T) }; - *value = *some_value; - *cursor += mem::size_of::(); - } - COption::None => { - output[*cursor] = 0; - *cursor += mem::size_of::(); - } - } - } - - /// Unpacks a COption from a compact slice - #[inline] - pub fn unpack_or(input: &[u8], cursor: &mut usize, error: E) -> Result, E> - where - T: Copy, - { - match input[*cursor] { - 0 => { - *cursor += mem::size_of::(); - Ok(COption::None) - } - 1 => { - *cursor += mem::size_of::(); - #[allow(clippy::cast_ptr_alignment)] - let result = unsafe { *(&input[*cursor] as *const u8 as *const T) }; - *cursor += mem::size_of::(); - Ok(COption::Some(result)) - } - _ => Err(error), - } - } } impl COption<&T> { @@ -1034,7 +985,6 @@ impl Into> for COption { #[cfg(test)] mod test { use super::*; - use solana_sdk::pubkey::Pubkey; #[test] fn test_from_rust_option() { @@ -1050,63 +1000,4 @@ mod test { let expected = c_option.into(); assert_eq!(option, expected); } - - #[test] - fn test_coption_packing() { - // Solana Pubkey - let option_pubkey = COption::Some(Pubkey::new(&[2u8; 32])); - let expected_size = mem::size_of::() + mem::size_of::(); - let mut output = vec![0u8; expected_size]; - let mut cursor = 0; - option_pubkey.pack(&mut output, &mut cursor); - - let mut expected = vec![1u8]; - expected.extend_from_slice(&[2u8; 32]); - assert_eq!(output, expected); - - let mut cursor = 0; - let unpacked = COption::unpack_or(&expected, &mut cursor, "Error".to_string()).unwrap(); - assert_eq!(unpacked, option_pubkey); - - let option_pubkey: COption = COption::None; - let expected_size = mem::size_of::(); - let mut output = vec![0u8; expected_size]; - let mut cursor = 0; - option_pubkey.pack(&mut output, &mut cursor); - - let expected = vec![0u8]; - assert_eq!(output, expected); - - let mut cursor = 0; - let unpacked = COption::unpack_or(&expected, &mut cursor, "Error".to_string()).unwrap(); - assert_eq!(unpacked, option_pubkey); - - // u64 - let option_pubkey = COption::Some(99u64); - let expected_size = mem::size_of::() + mem::size_of::(); - let mut output = vec![0u8; expected_size]; - let mut cursor = 0; - option_pubkey.pack(&mut output, &mut cursor); - - let mut expected = vec![1u8]; - expected.extend_from_slice(&[99, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(output, expected); - - let mut cursor = 0; - let unpacked = COption::unpack_or(&expected, &mut cursor, "Error".to_string()).unwrap(); - assert_eq!(unpacked, option_pubkey); - - let option_pubkey: COption = COption::None; - let expected_size = mem::size_of::(); - let mut output = vec![0u8; expected_size]; - let mut cursor = 0; - option_pubkey.pack(&mut output, &mut cursor); - - let expected = vec![0u8]; - assert_eq!(output, expected); - - let mut cursor = 0; - let unpacked = COption::unpack_or(&expected, &mut cursor, "Error".to_string()).unwrap(); - assert_eq!(unpacked, option_pubkey); - } } diff --git a/program/src/pack.rs b/program/src/pack.rs new file mode 100644 index 0000000..bf6a205 --- /dev/null +++ b/program/src/pack.rs @@ -0,0 +1,76 @@ +//! State transition types + +use crate::error::TokenError; +use solana_sdk::program_error::ProgramError; + +/// Check is a token state is initialized +pub trait IsInitialized { + /// Is initialized + fn is_initialized(&self) -> bool; +} + +/// Depends on Sized +pub trait Sealed: Sized {} + +/// Safely and efficiently (de)serialize account state +pub trait Pack: Sealed { + /// The length, in bytes, of the packed representation + const LEN: usize; + #[doc(hidden)] + fn pack_into_slice(&self, dst: &mut [u8]); + #[doc(hidden)] + fn unpack_from_slice(src: &[u8]) -> Result; + + /// Borrow `Self` from `input` for the duration of the call to `f`, but first check that `Self` + /// is initialized + #[inline(never)] + fn unpack_mut(input: &mut [u8], f: &mut F) -> Result + where + F: FnMut(&mut Self) -> Result, + Self: IsInitialized, + { + let mut t = unpack(input)?; + let u = f(&mut t)?; + pack(t, input)?; + Ok(u) + } + + /// Borrow `Self` from `input` for the duration of the call to `f`, without checking that + /// `Self` has been initialized + #[inline(never)] + fn unpack_unchecked_mut(input: &mut [u8], f: &mut F) -> Result + where + F: FnMut(&mut Self) -> Result, + { + let mut t = unpack_unchecked(input)?; + let u = f(&mut t)?; + pack(t, input)?; + Ok(u) + } +} + +fn pack(src: T, dst: &mut [u8]) -> Result<(), ProgramError> { + if dst.len() < T::LEN { + println!("dlen {:?} tlen {:?}", dst.len(), T::LEN); + return Err(ProgramError::InvalidAccountData); + } + src.pack_into_slice(dst); + Ok(()) +} + +fn unpack(input: &[u8]) -> Result { + let value: T = unpack_unchecked(input)?; + if value.is_initialized() { + Ok(value) + } else { + Err(TokenError::UninitializedState.into()) + } +} + +fn unpack_unchecked(input: &[u8]) -> Result { + if input.len() < T::LEN { + println!("ilen {:?} tlen {:?}", input.len(), T::LEN); + return Err(ProgramError::InvalidAccountData); + } + Ok(T::unpack_from_slice(input)?) +} diff --git a/program/src/processor.rs b/program/src/processor.rs index 4826f2a..d2f647e 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -6,7 +6,8 @@ use crate::{ error::TokenError, instruction::{is_valid_signer_index, AuthorityType, TokenInstruction}, option::COption, - state::{self, Account, AccountState, IsInitialized, Mint, Multisig}, + pack::{IsInitialized, Pack}, + state::{Account, AccountState, Mint, Multisig}, }; use num_traits::FromPrimitive; use solana_sdk::{ @@ -32,25 +33,26 @@ impl Processor { ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let mint_info = next_account_info(account_info_iter)?; - let mint_info_data_len = mint_info.data_len(); + let mint_data_len = mint_info.data_len(); let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; - let mut mint_info_data = mint_info.data.borrow_mut(); - let mut mint: &mut Mint = state::unpack_unchecked(&mut mint_info_data)?; - if mint.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } + let mut mint_data = mint_info.data.borrow_mut(); + Mint::unpack_unchecked_mut(&mut mint_data, &mut |mint: &mut Mint| { + if mint.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } - if !rent.is_exempt(mint_info.lamports(), mint_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } + if !rent.is_exempt(mint_info.lamports(), mint_data_len) { + return Err(TokenError::NotRentExempt.into()); + } - mint.mint_authority = COption::Some(mint_authority); - mint.decimals = decimals; - mint.is_initialized = true; - mint.freeze_authority = freeze_authority; + mint.mint_authority = COption::Some(mint_authority); + mint.decimals = decimals; + mint.is_initialized = true; + mint.freeze_authority = freeze_authority; - Ok(()) + Ok(()) + }) } /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. @@ -63,39 +65,40 @@ impl Processor { let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; let mut new_account_data = new_account_info.data.borrow_mut(); - let mut account: &mut Account = state::unpack_unchecked(&mut new_account_data)?; - if account.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } + Account::unpack_unchecked_mut(&mut new_account_data, &mut |account: &mut Account| { + if account.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } - if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } + if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) { + return Err(TokenError::NotRentExempt.into()); + } - if *mint_info.key != crate::native_mint::id() { - let mut mint_info_data = mint_info.data.borrow_mut(); - let _: &mut Mint = state::unpack(&mut mint_info_data) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - } + if *mint_info.key != crate::native_mint::id() { + let mut mint_info_data = mint_info.data.borrow_mut(); + Mint::unpack_mut(&mut mint_info_data, &mut |_| Ok(())) + .map_err(|_| Into::::into(TokenError::InvalidMint))?; + } - account.mint = *mint_info.key; - account.owner = *owner_info.key; - account.delegate = COption::None; - account.delegated_amount = 0; - account.state = AccountState::Initialized; - if *mint_info.key == crate::native_mint::id() { - let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); - account.is_native = COption::Some(rent_exempt_reserve); - account.amount = new_account_info - .lamports() - .checked_sub(rent_exempt_reserve) - .ok_or(TokenError::Overflow)?; - } else { - account.is_native = COption::None; - account.amount = 0; - }; + account.mint = *mint_info.key; + account.owner = *owner_info.key; + account.delegate = COption::None; + account.delegated_amount = 0; + account.state = AccountState::Initialized; + if *mint_info.key == crate::native_mint::id() { + let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); + account.is_native = COption::Some(rent_exempt_reserve); + account.amount = new_account_info + .lamports() + .checked_sub(rent_exempt_reserve) + .ok_or(TokenError::Overflow)?; + } else { + account.is_native = COption::None; + account.amount = 0; + }; - Ok(()) + Ok(()) + }) } /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. @@ -106,30 +109,34 @@ impl Processor { let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; let mut multisig_account_data = multisig_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack_unchecked(&mut multisig_account_data)?; - if multisig.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } + Multisig::unpack_unchecked_mut( + &mut multisig_account_data, + &mut |multisig: &mut Multisig| { + if multisig.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } - if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } + if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) { + return Err(TokenError::NotRentExempt.into()); + } - let signer_infos = account_info_iter.as_slice(); - multisig.m = m; - multisig.n = signer_infos.len() as u8; - if !is_valid_signer_index(multisig.n as usize) { - return Err(TokenError::InvalidNumberOfProvidedSigners.into()); - } - if !is_valid_signer_index(multisig.m as usize) { - return Err(TokenError::InvalidNumberOfRequiredSigners.into()); - } - for (i, signer_info) in signer_infos.iter().enumerate() { - multisig.signers[i] = *signer_info.key; - } - multisig.is_initialized = true; + let signer_infos = account_info_iter.as_slice(); + multisig.m = m; + multisig.n = signer_infos.len() as u8; + if !is_valid_signer_index(multisig.n as usize) { + return Err(TokenError::InvalidNumberOfProvidedSigners.into()); + } + if !is_valid_signer_index(multisig.m as usize) { + return Err(TokenError::InvalidNumberOfRequiredSigners.into()); + } + for (i, signer_info) in signer_infos.iter().enumerate() { + multisig.signers[i] = *signer_info.key; + } + multisig.is_initialized = true; - Ok(()) + Ok(()) + }, + ) } /// Processes a [Transfer](enum.TokenInstruction.html) instruction. @@ -157,82 +164,84 @@ impl Processor { } let mut source_data = source_account_info.data.borrow_mut(); - let mut source_account: &mut Account = state::unpack(&mut source_data)?; let mut dest_data = dest_account_info.data.borrow_mut(); - let mut dest_account: &mut Account = state::unpack(&mut dest_data)?; - - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if source_account.mint != dest_account.mint { - return Err(TokenError::MintMismatch.into()); - } - if source_account.is_frozen() || dest_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + Account::unpack_mut(&mut dest_data, &mut |dest_account: &mut Account| { + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + if source_account.mint != dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } + if source_account.is_frozen() || dest_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - if let Some((mint_account_info, expected_decimals)) = expected_mint_info { - if source_account.mint != *mint_account_info.key { - return Err(TokenError::MintMismatch.into()); - } + if let Some((mint_account_info, expected_decimals)) = expected_mint_info { + if source_account.mint != *mint_account_info.key { + return Err(TokenError::MintMismatch.into()); + } - let mut mint_info_data = mint_account_info.data.borrow_mut(); - let mint: &Mint = state::unpack_unchecked(&mut mint_info_data)?; + let mut mint_info_data = mint_account_info.data.borrow_mut(); + Mint::unpack_mut(&mut mint_info_data, &mut |mint: &mut Mint| { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + Ok(()) + })?; + } - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } + match source_account.delegate { + COption::Some(ref delegate) if authority_info.key == delegate => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount = source_account + .delegated_amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?, + }; - match source_account.delegate { - COption::Some(ref delegate) if authority_info.key == delegate => { - Self::validate_owner( - program_id, - delegate, - authority_info, - account_info_iter.as_slice(), - )?; - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - source_account.delegated_amount = source_account - .delegated_amount + source_account.amount = source_account + .amount .checked_sub(amount) .ok_or(TokenError::Overflow)?; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } - } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, - }; + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; - source_account.amount = source_account - .amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - dest_account.amount = dest_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - - if source_account.is_native() { - let source_starting_lamports = source_account_info.lamports(); - **source_account_info.lamports.borrow_mut() = source_starting_lamports - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; + if source_account.is_native() { + let source_starting_lamports = source_account_info.lamports(); + **source_account_info.lamports.borrow_mut() = source_starting_lamports + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; - let dest_starting_lamports = dest_account_info.lamports(); - **dest_account_info.lamports.borrow_mut() = dest_starting_lamports - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - } + let dest_starting_lamports = dest_account_info.lamports(); + **dest_account_info.lamports.borrow_mut() = dest_starting_lamports + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + } - Ok(()) + Ok(()) + }) + }) } /// Processes an [Approve](enum.TokenInstruction.html) instruction. @@ -254,36 +263,37 @@ impl Processor { let owner_info = next_account_info(account_info_iter)?; let mut source_data = source_account_info.data.borrow_mut(); - let mut source_account: &mut Account = state::unpack(&mut source_data)?; - - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if let Some((mint_account_info, expected_decimals)) = expected_mint_info { - if source_account.mint != *mint_account_info.key { - return Err(TokenError::MintMismatch.into()); + Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); } - let mut mint_info_data = mint_account_info.data.borrow_mut(); - let mint: &Mint = state::unpack_unchecked(&mut mint_info_data)?; + if let Some((mint_account_info, expected_decimals)) = expected_mint_info { + if source_account.mint != *mint_account_info.key { + return Err(TokenError::MintMismatch.into()); + } - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); + let mut mint_info_data = mint_account_info.data.borrow_mut(); + Mint::unpack_mut(&mut mint_info_data, &mut |mint: &mut Mint| { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + Ok(()) + })?; } - } - Self::validate_owner( - program_id, - &source_account.owner, - owner_info, - account_info_iter.as_slice(), - )?; + Self::validate_owner( + program_id, + &source_account.owner, + owner_info, + account_info_iter.as_slice(), + )?; - source_account.delegate = COption::Some(*delegate_info.key); - source_account.delegated_amount = amount; + source_account.delegate = COption::Some(*delegate_info.key); + source_account.delegated_amount = amount; - Ok(()) + Ok(()) + }) } /// Processes an [Revoke](enum.TokenInstruction.html) instruction. @@ -292,24 +302,25 @@ impl Processor { let source_account_info = next_account_info(account_info_iter)?; let mut source_data = source_account_info.data.borrow_mut(); - let mut source_account: &mut Account = state::unpack(&mut source_data)?; - let owner_info = next_account_info(account_info_iter)?; + Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + let owner_info = next_account_info(account_info_iter)?; - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - Self::validate_owner( - program_id, - &source_account.owner, - owner_info, - account_info_iter.as_slice(), - )?; + Self::validate_owner( + program_id, + &source_account.owner, + owner_info, + account_info_iter.as_slice(), + )?; - source_account.delegate = COption::None; - source_account.delegated_amount = 0; + source_account.delegate = COption::None; + source_account.delegated_amount = 0; - Ok(()) + Ok(()) + }) } /// Processes a [SetAuthority](enum.TokenInstruction.html) instruction. @@ -325,78 +336,80 @@ impl Processor { if account_info.data_len() == size_of::() { let mut account_data = account_info.data.borrow_mut(); - let mut account: &mut Account = state::unpack(&mut account_data)?; - - if account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - match authority_type { - AuthorityType::AccountHolder => { - Self::validate_owner( - program_id, - &account.owner, - authority_info, - account_info_iter.as_slice(), - )?; + Account::unpack_mut(&mut account_data, &mut |account: &mut Account| { + if account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - if let COption::Some(authority) = new_authority { - account.owner = authority; - } else { - return Err(TokenError::InvalidInstruction.into()); + match authority_type { + AuthorityType::AccountHolder => { + Self::validate_owner( + program_id, + &account.owner, + authority_info, + account_info_iter.as_slice(), + )?; + + if let COption::Some(authority) = new_authority { + account.owner = authority; + } else { + return Err(TokenError::InvalidInstruction.into()); + } + } + AuthorityType::CloseAccount => { + let authority = account.close_authority.unwrap_or(account.owner); + Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + )?; + account.close_authority = new_authority; + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); } } - AuthorityType::CloseAccount => { - let authority = account.close_authority.unwrap_or(account.owner); - Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - )?; - account.close_authority = new_authority; - } - _ => { - return Err(TokenError::AuthorityTypeNotSupported.into()); - } - } + Ok(()) + })?; } else if account_info.data_len() == size_of::() { - let mut account_data = account_info.data.borrow_mut(); - let mut mint: &mut Mint = state::unpack(&mut account_data)?; - - match authority_type { - AuthorityType::MintTokens => { - // Once a mint's supply is fixed, it cannot be undone by setting a new - // mint_authority - let mint_authority = mint - .mint_authority - .ok_or(Into::::into(TokenError::FixedSupply))?; - Self::validate_owner( - program_id, - &mint_authority, - authority_info, - account_info_iter.as_slice(), - )?; - mint.mint_authority = new_authority; - } - AuthorityType::FreezeAccount => { - // Once a mint's freeze authority is disabled, it cannot be re-enabled by - // setting a new freeze_authority - let freeze_authority = mint - .freeze_authority - .ok_or(Into::::into(TokenError::MintCannotFreeze))?; - Self::validate_owner( - program_id, - &freeze_authority, - authority_info, - account_info_iter.as_slice(), - )?; - mint.freeze_authority = new_authority; - } - _ => { - return Err(TokenError::AuthorityTypeNotSupported.into()); + let mut mint_data = account_info.data.borrow_mut(); + Mint::unpack_mut(&mut mint_data, &mut |mint: &mut Mint| { + match authority_type { + AuthorityType::MintTokens => { + // Once a mint's supply is fixed, it cannot be undone by setting a new + // mint_authority + let mint_authority = mint + .mint_authority + .ok_or(Into::::into(TokenError::FixedSupply))?; + Self::validate_owner( + program_id, + &mint_authority, + authority_info, + account_info_iter.as_slice(), + )?; + mint.mint_authority = new_authority; + } + AuthorityType::FreezeAccount => { + // Once a mint's freeze authority is disabled, it cannot be re-enabled by + // setting a new freeze_authority + let freeze_authority = mint + .freeze_authority + .ok_or(Into::::into(TokenError::MintCannotFreeze))?; + Self::validate_owner( + program_id, + &freeze_authority, + authority_info, + account_info_iter.as_slice(), + )?; + mint.freeze_authority = new_authority; + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); + } } - } + Ok(()) + })?; } else { return Err(ProgramError::InvalidArgument); } @@ -417,53 +430,49 @@ impl Processor { let owner_info = next_account_info(account_info_iter)?; let mut dest_account_data = dest_account_info.data.borrow_mut(); - let mut dest_account: &mut Account = state::unpack(&mut dest_account_data)?; - - if dest_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if dest_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if mint_info.key != &dest_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - let mut mint_info_data = mint_info.data.borrow_mut(); - let mint: &mut Mint = state::unpack(&mut mint_info_data)?; - - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); + Account::unpack_mut(&mut dest_account_data, &mut |dest_account: &mut Account| { + if dest_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); } - } - match mint.mint_authority { - COption::Some(mint_authority) => { - Self::validate_owner( - program_id, - &mint_authority, - owner_info, - account_info_iter.as_slice(), - )?; + if dest_account.is_native() { + return Err(TokenError::NativeNotSupported.into()); } - COption::None => { - return Err(TokenError::FixedSupply.into()); + if mint_info.key != &dest_account.mint { + return Err(TokenError::MintMismatch.into()); } - } - dest_account.amount = dest_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; + let mut mint_info_data = mint_info.data.borrow_mut(); + Mint::unpack_mut(&mut mint_info_data, &mut |mint: &mut Mint| { + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + match mint.mint_authority { + COption::Some(mint_authority) => Self::validate_owner( + program_id, + &mint_authority, + owner_info, + account_info_iter.as_slice(), + )?, + COption::None => return Err(TokenError::FixedSupply.into()), + } - mint.supply = mint - .supply - .checked_add(amount) - .ok_or(TokenError::Overflow)?; + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; - Ok(()) + mint.supply = mint + .supply + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + + Ok(()) + }) + }) } /// Processes a [Burn](enum.TokenInstruction.html) instruction. @@ -480,68 +489,68 @@ impl Processor { let authority_info = next_account_info(account_info_iter)?; let mut mint_data = mint_info.data.borrow_mut(); - let mint: &mut Mint = state::unpack(&mut mint_data)?; - let mut source_data = source_account_info.data.borrow_mut(); - let source_account: &mut Account = state::unpack(&mut source_data)?; - - if source_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if mint_info.key != &source_account.mint { - return Err(TokenError::MintMismatch.into()); - } - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } + Mint::unpack_mut(&mut mint_data, &mut |mint: &mut Mint| { + Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + if source_account.is_native() { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - match source_account.delegate { - COption::Some(ref delegate) if authority_info.key == delegate => { - Self::validate_owner( - program_id, - delegate, - authority_info, - account_info_iter.as_slice(), - )?; + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); + match source_account.delegate { + COption::Some(ref delegate) if authority_info.key == delegate => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; + + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount = source_account + .delegated_amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?, } - source_account.delegated_amount = source_account - .delegated_amount + + source_account.amount = source_account + .amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + mint.supply = mint + .supply .checked_sub(amount) .ok_or(TokenError::Overflow)?; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } - } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, - } - - source_account.amount = source_account - .amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - mint.supply = mint - .supply - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - Ok(()) + Ok(()) + }) + }) } /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. @@ -552,31 +561,31 @@ impl Processor { let authority_info = next_account_info(account_info_iter)?; let mut source_data = source_account_info.data.borrow_mut(); - let source_account: &mut Account = state::unpack(&mut source_data)?; - - if !source_account.is_native() && source_account.amount != 0 { - return Err(TokenError::NonNativeHasBalance.into()); - } + Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + if !source_account.is_native() && source_account.amount != 0 { + return Err(TokenError::NonNativeHasBalance.into()); + } - let authority = source_account - .close_authority - .unwrap_or(source_account.owner); - Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - )?; + let authority = source_account + .close_authority + .unwrap_or(source_account.owner); + Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + )?; - let dest_starting_lamports = dest_account_info.lamports(); - **dest_account_info.lamports.borrow_mut() = dest_starting_lamports - .checked_add(source_account_info.lamports()) - .ok_or(TokenError::Overflow)?; + let dest_starting_lamports = dest_account_info.lamports(); + **dest_account_info.lamports.borrow_mut() = dest_starting_lamports + .checked_add(source_account_info.lamports()) + .ok_or(TokenError::Overflow)?; - **source_account_info.lamports.borrow_mut() = 0; - source_account.amount = 0; + **source_account_info.lamports.borrow_mut() = 0; + source_account.amount = 0; - Ok(()) + Ok(()) + }) } /// Processes a [FreezeAccount](enum.TokenInstruction.html) or a @@ -592,42 +601,39 @@ impl Processor { let authority_info = next_account_info(account_info_iter)?; let mut source_data = source_account_info.data.borrow_mut(); - let source_account: &mut Account = state::unpack(&mut source_data)?; - - if source_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if mint_info.key != &source_account.mint { - return Err(TokenError::MintMismatch.into()); - } - if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { - return Err(TokenError::InvalidState.into()); - } - - let mut mint_info_data = mint_info.data.borrow_mut(); - let mint: &mut Mint = state::unpack(&mut mint_info_data)?; - - match mint.freeze_authority { - COption::Some(authority) => { - Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - )?; + Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + if source_account.is_native() { + return Err(TokenError::NativeNotSupported.into()); } - COption::None => { - return Err(TokenError::MintCannotFreeze.into()); + if mint_info.key != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { + return Err(TokenError::InvalidState.into()); } - } - - source_account.state = if freeze { - AccountState::Frozen - } else { - AccountState::Initialized - }; - Ok(()) + let mut mint_data = mint_info.data.borrow_mut(); + Mint::unpack_mut( + &mut mint_data, + &mut |mint: &mut Mint| match mint.freeze_authority { + COption::Some(authority) => Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + ), + COption::None => Err(TokenError::MintCannotFreeze.into()), + }, + )?; + + source_account.state = if freeze { + AccountState::Frozen + } else { + AccountState::Initialized + }; + + Ok(()) + }) } /// Processes an [Instruction](enum.Instruction.html). @@ -723,19 +729,21 @@ impl Processor { && owner_account_info.data_len() == std::mem::size_of::() { let mut owner_data = owner_account_info.data.borrow_mut(); - let multisig: &mut Multisig = state::unpack(&mut owner_data)?; - let mut num_signers = 0; - for signer in signers.iter() { - if multisig.signers[0..multisig.n as usize].contains(signer.key) { - if !signer.is_signer { - return Err(ProgramError::MissingRequiredSignature); + Multisig::unpack_mut(&mut owner_data, &mut |multisig: &mut Multisig| { + let mut num_signers = 0; + for signer in signers.iter() { + if multisig.signers[0..multisig.n as usize].contains(signer.key) { + if !signer.is_signer { + return Err(ProgramError::MissingRequiredSignature); + } + num_signers += 1; } - num_signers += 1; } - } - if num_signers < multisig.m { - return Err(ProgramError::MissingRequiredSignature); - } + if num_signers < multisig.m { + return Err(ProgramError::MissingRequiredSignature); + } + Ok(()) + })?; } else if !owner_account_info.is_signer { return Err(ProgramError::MissingRequiredSignature); } @@ -904,8 +912,11 @@ mod tests { vec![&mut mint2_account, &mut rent_sysvar], ) .unwrap(); - let mint2: &mut Mint = state::unpack(&mut mint2_account.data).unwrap(); - assert_eq!(mint2.freeze_authority, COption::Some(owner_key)); + Mint::unpack_unchecked_mut(&mut mint2_account.data, &mut |mint: &mut Mint| { + assert_eq!(mint.freeze_authority, COption::Some(owner_key)); + Ok(()) + }) + .unwrap(); } #[test] @@ -1065,8 +1076,11 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut mismatch_account.data).unwrap(); - account.mint = mint2_key; + Account::unpack_unchecked_mut(&mut mismatch_account.data, &mut |account: &mut Account| { + account.mint = mint2_key; + Ok(()) + }) + .unwrap(); // mint to account do_process_instruction( @@ -1292,8 +1306,11 @@ mod tests { ) .unwrap() } - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, 1000); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 1000); + Ok(()) + }) + .unwrap(); // insufficient funds assert_eq!( @@ -1447,17 +1464,20 @@ mod tests { vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); - let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - assert_eq!( - *mint, - Mint { - mint_authority: COption::Some(owner_key), - supply: 0, - decimals, - is_initialized: true, - freeze_authority: COption::None, - } - ); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + assert_eq!( + *mint, + Mint { + mint_authority: COption::Some(owner_key), + supply: 0, + decimals, + is_initialized: true, + freeze_authority: COption::None, + } + ); + Ok(()) + }) + .unwrap(); // create account do_process_instruction( @@ -1477,6 +1497,12 @@ mod tests { vec![&mut mint_account, &mut account_account, &mut owner_account], ) .unwrap(); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |_| Ok(())).unwrap(); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 42); + Ok(()) + }) + .unwrap(); // mint to 2, with incorrect decimals assert_eq!( @@ -1496,9 +1522,12 @@ mod tests { ) ); - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(dest_account.amount, 42); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |_| Ok(())).unwrap(); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 42); + Ok(()) + }) + .unwrap(); // mint to 2 do_process_instruction( @@ -1515,10 +1544,12 @@ mod tests { vec![&mut mint_account, &mut account_account, &mut owner_account], ) .unwrap(); - - let _: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(dest_account.amount, 84); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |_| Ok(())).unwrap(); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 84); + Ok(()) + }) + .unwrap(); } #[test] @@ -2135,8 +2166,11 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut mismatch_account.data).unwrap(); - account.mint = mint2_key; + Account::unpack_unchecked_mut(&mut mismatch_account.data, &mut |account: &mut Account| { + account.mint = mint2_key; + Ok(()) + }) + .unwrap(); // mint to do_process_instruction( @@ -2145,10 +2179,16 @@ mod tests { ) .unwrap(); - let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - assert_eq!(mint.supply, 42); - let dest_account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(dest_account.amount, 42); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + assert_eq!(mint.supply, 42); + Ok(()) + }) + .unwrap(); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 42); + Ok(()) + }) + .unwrap(); // mint to another account to test supply accumulation do_process_instruction( @@ -2157,10 +2197,16 @@ mod tests { ) .unwrap(); - let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - assert_eq!(mint.supply, 84); - let dest_account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert_eq!(dest_account.amount, 42); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + assert_eq!(mint.supply, 84); + Ok(()) + }) + .unwrap(); + Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 42); + Ok(()) + }) + .unwrap(); // missing signer let mut instruction = @@ -2321,8 +2367,11 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut mismatch_account.data).unwrap(); - account.mint = mint2_key; + Account::unpack_unchecked_mut(&mut mismatch_account.data, &mut |account: &mut Account| { + account.mint = mint2_key; + Ok(()) + }) + .unwrap(); // mint to account do_process_instruction( @@ -2388,10 +2437,17 @@ mod tests { ) .unwrap(); - let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - assert_eq!(mint.supply, 1000 - 42); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + assert_eq!(mint.supply, 1000 - 42); + + Ok(()) + }) + .unwrap(); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 1000 - 42); + Ok(()) + }) + .unwrap(); // insufficient funds assert_eq!( @@ -2458,10 +2514,16 @@ mod tests { .unwrap(); // match - let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - assert_eq!(mint.supply, 1000 - 42 - 84); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42 - 84); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + assert_eq!(mint.supply, 1000 - 42 - 84); + Ok(()) + }) + .unwrap(); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 1000 - 42 - 84); + Ok(()) + }) + .unwrap(); // insufficient funds approved via delegate assert_eq!( @@ -2908,11 +2970,14 @@ mod tests { } let mut lamports = 0; let mut data = vec![0; size_of::()]; - let mut multisig: &mut Multisig = state::unpack_unchecked(&mut data).unwrap(); - multisig.m = MAX_SIGNERS as u8; - multisig.n = MAX_SIGNERS as u8; - multisig.signers = signer_keys; - multisig.is_initialized = true; + Multisig::unpack_unchecked_mut(&mut data, &mut |multisig: &mut Multisig| { + multisig.m = MAX_SIGNERS as u8; + multisig.n = MAX_SIGNERS as u8; + multisig.signers = signer_keys; + multisig.is_initialized = true; + Ok(()) + }) + .unwrap(); let owner_account_info = AccountInfo::new( &owner_key, false, @@ -2930,17 +2995,23 @@ mod tests { // 1 of 11 { let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 1; + Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + multisig.m = 1; + Ok(()) + }) + .unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); // 2:1 { let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 1; + Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + multisig.m = 2; + multisig.n = 1; + Ok(()) + }) + .unwrap(); } assert_eq!( Err(ProgramError::MissingRequiredSignature), @@ -2950,18 +3021,24 @@ mod tests { // 0:11 { let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 0; - multisig.n = 11; + Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + multisig.m = 0; + multisig.n = 11; + Ok(()) + }) + .unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); // 2:11 but 0 provided { let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 11; + Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + multisig.m = 2; + multisig.n = 11; + Ok(()) + }) + .unwrap(); } assert_eq!( Err(ProgramError::MissingRequiredSignature), @@ -2970,9 +3047,12 @@ mod tests { // 2:11 but 1 provided { let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 11; + Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + multisig.m = 2; + multisig.n = 11; + Ok(()) + }) + .unwrap(); } assert_eq!( Err(ProgramError::MissingRequiredSignature), @@ -2982,9 +3062,12 @@ mod tests { // 2:11, 2 from middle provided { let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 11; + Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + multisig.m = 2; + multisig.n = 11; + Ok(()) + }) + .unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[5..7]) .unwrap(); @@ -2992,9 +3075,12 @@ mod tests { // 11:11, one is not a signer { let mut data_ref_mut = owner_account_info.data.borrow_mut(); - let mut multisig: &mut Multisig = state::unpack(&mut data_ref_mut).unwrap(); - multisig.m = 2; - multisig.n = 11; + Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + multisig.m = 2; // TODO 11? + multisig.n = 11; + Ok(()) + }) + .unwrap(); } signers[5].is_signer = false; assert_eq!( @@ -3067,8 +3153,11 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, 42); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 42); + Ok(()) + }) + .unwrap(); // initialize native account do_process_instruction( @@ -3087,9 +3176,12 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 42); + Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + assert!(account.is_native()); + assert_eq!(account.amount, 42); + Ok(()) + }) + .unwrap(); // close non-native account with balance assert_eq!( @@ -3135,10 +3227,13 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap(); assert_eq!(account_account.lamports, 0); - assert_eq!(account.amount, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 0); + Ok(()) + }) + .unwrap(); // fund and initialize new non-native account to test close authority let account_key = pubkey_rand(); @@ -3197,8 +3292,12 @@ mod tests { ) .unwrap(); assert_eq!(account_account.lamports, 0); - assert_eq!(account.amount, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, 0); + Ok(()) + }) + .unwrap(); // close native account do_process_instruction( @@ -3210,14 +3309,17 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack_unchecked(&mut account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account_account.lamports, 0); - assert_eq!(account.amount, 0); - assert_eq!( - account3_account.lamports, - 3 * account_minimum_balance() + 2 + 42 - ); + Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + assert!(account.is_native()); + assert_eq!(account_account.lamports, 0); + assert_eq!(account.amount, 0); + assert_eq!( + account3_account.lamports, + 3 * account_minimum_balance() + 2 + 42 + ); + Ok(()) + }) + .unwrap(); } #[test] @@ -3257,9 +3359,12 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert!(account.is_native()); + assert_eq!(account.amount, 40); + Ok(()) + }) + .unwrap(); // initialize native account do_process_instruction( @@ -3278,9 +3383,12 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); + Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + assert!(account.is_native()); + assert_eq!(account.amount, 0); + Ok(()) + }) + .unwrap(); // mint_to unsupported assert_eq!( @@ -3368,15 +3476,20 @@ mod tests { ], ) .unwrap(); - - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert!(account.is_native()); assert_eq!(account_account.lamports, account_minimum_balance()); - assert_eq!(account.amount, 0); - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - assert!(account.is_native()); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert!(account.is_native()); + assert_eq!(account.amount, 0); + Ok(()) + }) + .unwrap(); assert_eq!(account2_account.lamports, account_minimum_balance() + 40); - assert_eq!(account.amount, 40); + Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + assert!(account.is_native()); + assert_eq!(account.amount, 40); + Ok(()) + }) + .unwrap(); // close native account do_process_instruction( @@ -3388,11 +3501,14 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack_unchecked(&mut account_account.data).unwrap(); - assert!(account.is_native()); assert_eq!(account_account.lamports, 0); - assert_eq!(account.amount, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert!(account.is_native()); + assert_eq!(account.amount, 0); + Ok(()) + }) + .unwrap(); } #[test] @@ -3464,8 +3580,11 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, u64::MAX); + Ok(()) + }) + .unwrap(); // attempt to mint one more to account assert_eq!( @@ -3487,8 +3606,11 @@ mod tests { ], ) ); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, u64::MAX); + Ok(()) + }) + .unwrap(); // atttempt to mint one more to the other account assert_eq!( @@ -3517,8 +3639,11 @@ mod tests { vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX - 100); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, u64::MAX - 100); + Ok(()) + }) + .unwrap(); do_process_instruction( mint_to( @@ -3537,12 +3662,18 @@ mod tests { ], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.amount, u64::MAX); + Ok(()) + }) + .unwrap(); // manipulate account balance to attempt overflow transfer - let account: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - account.amount = 1; + Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + account.amount = 1; + Ok(()) + }) + .unwrap(); assert_eq!( Err(TokenError::Overflow.into()), @@ -3620,8 +3751,11 @@ mod tests { .unwrap(); // no transfer if either account is frozen - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - account.state = AccountState::Frozen; + Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + account.state = AccountState::Frozen; + Ok(()) + }) + .unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), do_process_instruction( @@ -3642,10 +3776,16 @@ mod tests { ) ); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - account.state = AccountState::Initialized; - let account2: &mut Account = state::unpack(&mut account2_account.data).unwrap(); - account2.state = AccountState::Frozen; + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + account.state = AccountState::Initialized; + Ok(()) + }) + .unwrap(); + Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + account.state = AccountState::Frozen; + Ok(()) + }) + .unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), do_process_instruction( @@ -3667,8 +3807,11 @@ mod tests { ); // no approve if account is frozen - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - account.state = AccountState::Frozen; + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + account.state = AccountState::Frozen; + Ok(()) + }) + .unwrap(); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); assert_eq!( @@ -3692,9 +3835,12 @@ mod tests { ); // no revoke if account is frozen - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - account.delegate = COption::Some(delegate_key); - account.delegated_amount = 100; + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + account.delegate = COption::Some(delegate_key); + account.delegated_amount = 100; + Ok(()) + }) + .unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), do_process_instruction( @@ -3793,8 +3939,11 @@ mod tests { ); // missing freeze_authority - let mint: &mut Mint = state::unpack(&mut mint_account.data).unwrap(); - mint.freeze_authority = COption::Some(owner_key); + Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + mint.freeze_authority = COption::Some(owner_key); + Ok(()) + }) + .unwrap(); assert_eq!( Err(TokenError::OwnerMismatch.into()), do_process_instruction( @@ -3818,8 +3967,11 @@ mod tests { vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Frozen); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.state, AccountState::Frozen); + Ok(()) + }) + .unwrap(); // check explicit freeze assert_eq!( @@ -3845,7 +3997,10 @@ mod tests { vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); - let account: &mut Account = state::unpack(&mut account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Initialized); + Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + assert_eq!(account.state, AccountState::Initialized); + Ok(()) + }) + .unwrap(); } } diff --git a/program/src/state.rs b/program/src/state.rs index 5b3981c..08de37e 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -1,8 +1,18 @@ //! State transition types -use crate::{error::TokenError, instruction::MAX_SIGNERS, option::COption}; +use crate::{ + instruction::MAX_SIGNERS, + option::COption, + pack::{IsInitialized, Pack, Sealed}, +}; +use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; +use num_enum::TryFromPrimitive; use solana_sdk::{program_error::ProgramError, pubkey::Pubkey}; -use std::mem::size_of; + +impl Sealed for Option {} +impl Sealed for Mint {} +impl Sealed for Account {} +impl Sealed for Multisig {} /// Mint data. #[repr(C)] @@ -26,6 +36,52 @@ impl IsInitialized for Mint { self.is_initialized } } +impl Pack for Mint { + const LEN: usize = 82; + fn unpack_from_slice(src: &[u8]) -> Result { + let src = array_ref![src, 0, 82]; + let (mint_authority, supply, decimals, is_initialized, freeze_authority) = + array_refs![src, 36, 8, 1, 1, 36]; + let mint_authority = unpack_coption_key(mint_authority)?; + let supply = u64::from_le_bytes(*supply); + let decimals = decimals[0]; + let is_initialized = match is_initialized { + [0] => false, + [1] => true, + _ => return Err(ProgramError::InvalidAccountData), + }; + let freeze_authority = unpack_coption_key(freeze_authority)?; + Ok(Mint { + mint_authority, + supply, + decimals, + is_initialized, + freeze_authority, + }) + } + fn pack_into_slice(&self, dst: &mut [u8]) { + let dst = array_mut_ref![dst, 0, 82]; + let ( + mint_authority_dst, + supply_dst, + decimals_dst, + is_initialized_dst, + freeze_authority_dst, + ) = mut_array_refs![dst, 36, 8, 1, 1, 36]; + let &Mint { + ref mint_authority, + supply, + decimals, + is_initialized, + ref freeze_authority, + } = self; + pack_coption_key(mint_authority, mint_authority_dst); + *supply_dst = supply.to_le_bytes(); + decimals_dst[0] = decimals; + is_initialized_dst[0] = is_initialized as u8; + pack_coption_key(freeze_authority, freeze_authority_dst); + } +} /// Account data. #[repr(C)] @@ -66,10 +122,60 @@ impl IsInitialized for Account { self.state != AccountState::Uninitialized } } +impl Pack for Account { + const LEN: usize = 165; + fn unpack_from_slice(src: &[u8]) -> Result { + let src = array_ref![src, 0, 165]; + let (mint, owner, amount, delegate, state, is_native, delegated_amount, close_authority) = + array_refs![src, 32, 32, 8, 36, 1, 12, 8, 36]; + Ok(Account { + mint: Pubkey::new_from_array(*mint), + owner: Pubkey::new_from_array(*owner), + amount: u64::from_le_bytes(*amount), + delegate: unpack_coption_key(delegate)?, + state: AccountState::try_from_primitive(state[0]) + .or(Err(ProgramError::InvalidAccountData))?, + is_native: unpack_coption_u64(is_native)?, + delegated_amount: u64::from_le_bytes(*delegated_amount), + close_authority: unpack_coption_key(close_authority)?, + }) + } + fn pack_into_slice(&self, dst: &mut [u8]) { + let dst = array_mut_ref![dst, 0, 165]; + let ( + mint_dst, + owner_dst, + amount_dst, + delegate_dst, + state_dst, + is_native_dst, + delegated_amount_dst, + close_authority_dst, + ) = mut_array_refs![dst, 32, 32, 8, 36, 1, 12, 8, 36]; + let &Account { + ref mint, + ref owner, + amount, + ref delegate, + state, + ref is_native, + delegated_amount, + ref close_authority, + } = self; + mint_dst.copy_from_slice(mint.as_ref()); + owner_dst.copy_from_slice(owner.as_ref()); + *amount_dst = amount.to_le_bytes(); + pack_coption_key(delegate, delegate_dst); + state_dst[0] = state as u8; + pack_coption_u64(is_native, is_native_dst); + *delegated_amount_dst = delegated_amount.to_le_bytes(); + pack_coption_key(close_authority, close_authority_dst); + } +} /// Account state. #[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive)] pub enum AccountState { /// Account is not yet initialized Uninitialized, @@ -105,26 +211,79 @@ impl IsInitialized for Multisig { self.is_initialized } } - -/// Check is a token state is initialized -pub trait IsInitialized { - /// Is initialized - fn is_initialized(&self) -> bool; +impl Pack for Multisig { + const LEN: usize = 355; + fn unpack_from_slice(src: &[u8]) -> Result { + let src = array_ref![src, 0, 355]; + #[allow(clippy::ptr_offset_with_cast)] + let (m, n, is_initialized, signers_flat) = array_refs![src, 1, 1, 1, 32 * MAX_SIGNERS]; + let mut result = Multisig { + m: m[0], + n: n[0], + is_initialized: match is_initialized { + [0] => false, + [1] => true, + _ => return Err(ProgramError::InvalidAccountData), + }, + signers: [Pubkey::new_from_array([0u8; 32]); MAX_SIGNERS], + }; + for (src, dst) in signers_flat.chunks(32).zip(result.signers.iter_mut()) { + *dst = Pubkey::new(src); + } + Ok(result) + } + fn pack_into_slice(&self, dst: &mut [u8]) { + let dst = array_mut_ref![dst, 0, 355]; + #[allow(clippy::ptr_offset_with_cast)] + let (m, n, is_initialized, signers_flat) = mut_array_refs![dst, 1, 1, 1, 32 * MAX_SIGNERS]; + *m = [self.m]; + *n = [self.n]; + *is_initialized = [self.is_initialized as u8]; + for (i, src) in self.signers.iter().enumerate() { + let dst_array = array_mut_ref![signers_flat, 32 * i, 32]; + dst_array.copy_from_slice(src.as_ref()); + } + } } -/// Unpacks a token state from a bytes buffer while assuring that the state is initialized. -pub fn unpack(input: &mut [u8]) -> Result<&mut T, ProgramError> { - let mut_ref: &mut T = unpack_unchecked(input)?; - if !mut_ref.is_initialized() { - return Err(TokenError::UninitializedState.into()); +// Helpers +fn pack_coption_key(src: &COption, dst: &mut [u8; 36]) { + let (tag, body) = mut_array_refs![dst, 4, 32]; + match src { + COption::Some(key) => { + *tag = [1, 0, 0, 0]; + body.copy_from_slice(key.as_ref()); + } + COption::None => { + *tag = [0; 4]; + } + } +} +fn unpack_coption_key(src: &[u8; 36]) -> Result, ProgramError> { + let (tag, body) = array_refs![src, 4, 32]; + match *tag { + [0, 0, 0, 0] => Ok(COption::None), + [1, 0, 0, 0] => Ok(COption::Some(Pubkey::new_from_array(*body))), + _ => Err(ProgramError::InvalidAccountData), + } +} +fn pack_coption_u64(src: &COption, dst: &mut [u8; 12]) { + let (tag, body) = mut_array_refs![dst, 4, 8]; + match src { + COption::Some(amount) => { + *tag = [1, 0, 0, 0]; + *body = amount.to_le_bytes(); + } + COption::None => { + *tag = [0; 4]; + } } - Ok(mut_ref) } -/// Unpacks a token state from a bytes buffer without checking that the state is initialized. -pub fn unpack_unchecked(input: &mut [u8]) -> Result<&mut T, ProgramError> { - if input.len() != size_of::() { - return Err(ProgramError::InvalidAccountData); +fn unpack_coption_u64(src: &[u8; 12]) -> Result, ProgramError> { + let (tag, body) = array_refs![src, 4, 8]; + match *tag { + [0, 0, 0, 0] => Ok(COption::None), + [1, 0, 0, 0] => Ok(COption::Some(u64::from_le_bytes(*body))), + _ => Err(ProgramError::InvalidAccountData), } - #[allow(clippy::cast_ptr_alignment)] - Ok(unsafe { &mut *(&mut input[0] as *mut u8 as *mut T) }) } From 6aa0eaec42c6b754f27ad9f583a94c3ec40f384e Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 27 Aug 2020 22:28:49 -0700 Subject: [PATCH 046/335] Fix various quotes in documentation --- program/src/instruction.rs | 66 +++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 8e1a045..5052237 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -82,13 +82,13 @@ pub enum TokenInstruction { /// * Single owner/delegate /// 0. `[writable]` The source account. /// 1. `[writable]` The destination account. - /// 2. '[signer]' The source account's owner/delegate. + /// 2. `[signer]` The source account's owner/delegate. /// /// * Multisignature owner/delegate /// 0. `[writable]` The source account. /// 1. `[writable]` The destination account. - /// 2. '[]' The source account's multisignature owner/delegate. - /// 3. ..3+M '[signer]' M signer accounts. + /// 2. `[]` The source account's multisignature owner/delegate. + /// 3. ..3+M `[signer]` M signer accounts. Transfer { /// The amount of tokens to transfer. amount: u64, @@ -106,8 +106,8 @@ pub enum TokenInstruction { /// * Multisignature owner /// 0. `[writable]` The source account. /// 1. `[]` The delegate. - /// 2. '[]' The source account's multisignature owner. - /// 3. ..3+M '[signer]' M signer accounts + /// 2. `[]` The source account's multisignature owner. + /// 3. ..3+M `[signer]` M signer accounts Approve { /// The amount of tokens the delegate is approved for. amount: u64, @@ -122,8 +122,8 @@ pub enum TokenInstruction { /// /// * Multisignature owner /// 0. `[writable]` The source account. - /// 1. '[]' The source account's multisignature owner. - /// 2. ..2+M '[signer]' M signer accounts + /// 1. `[]` The source account's multisignature owner. + /// 2. ..2+M `[signer]` M signer accounts Revoke, /// Sets a new authority of a mint or account. /// @@ -136,7 +136,7 @@ pub enum TokenInstruction { /// * Multisignature authority /// 0. `[writable]` The mint or account to change the authority of. /// 1. `[]` The mint's or account's multisignature authority. - /// 2. ..2+M '[signer]' M signer accounts + /// 2. ..2+M `[signer]` M signer accounts SetAuthority { /// The type of authority to update. authority_type: AuthorityType, @@ -156,7 +156,7 @@ pub enum TokenInstruction { /// 0. `[writable]` The mint. /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M '[signer]' M signer accounts. + /// 3. ..3+M `[signer]` M signer accounts. MintTo { /// The amount of new tokens to mint. amount: u64, @@ -168,7 +168,7 @@ pub enum TokenInstruction { /// /// * Single owner/delegate /// 0. `[writable]` The account to burn from. - /// 1. '[writable]' The token mint. + /// 1. `[writable]` The token mint. /// 2. `[signer]` The account's owner/delegate. /// /// * Multisignature owner/delegate @@ -187,14 +187,14 @@ pub enum TokenInstruction { /// /// * Single owner /// 0. `[writable]` The account to close. - /// 1. '[writable]' The destination account. + /// 1. `[writable]` The destination account. /// 2. `[signer]` The account's owner. /// /// * Multisignature owner /// 0. `[writable]` The account to close. - /// 1. '[writable]' The destination account. + /// 1. `[writable]` The destination account. /// 2. `[]` The account's multisignature owner. - /// 3. ..3+M '[signer]' M signer accounts. + /// 3. ..3+M `[signer]` M signer accounts. CloseAccount, /// Freeze an Initialized account using the Mint's freeze_authority (if set). /// @@ -202,14 +202,14 @@ pub enum TokenInstruction { /// /// * Single owner /// 0. `[writable]` The account to freeze. - /// 1. '[]' The token mint. + /// 1. `[]` The token mint. /// 2. `[signer]` The mint freeze authority. /// /// * Multisignature owner /// 0. `[writable]` The account to freeze. - /// 1. '[]' The token mint. + /// 1. `[]` The token mint. /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M '[signer]' M signer accounts. + /// 3. ..3+M `[signer]` M signer accounts. FreezeAccount, /// Thaw a Frozen account using the Mint's freeze_authority (if set). /// @@ -217,14 +217,14 @@ pub enum TokenInstruction { /// /// * Single owner /// 0. `[writable]` The account to freeze. - /// 1. '[]' The token mint. + /// 1. `[]` The token mint. /// 2. `[signer]` The mint freeze authority. /// /// * Multisignature owner /// 0. `[writable]` The account to freeze. - /// 1. '[]' The token mint. + /// 1. `[]` The token mint. /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M '[signer]' M signer accounts. + /// 3. ..3+M `[signer]` M signer accounts. ThawAccount, /// Transfers tokens from one account to another either directly or via a delegate. If this @@ -239,16 +239,16 @@ pub enum TokenInstruction { /// /// * Single owner/delegate /// 0. `[writable]` The source account. - /// 1. '[]' The token mint. + /// 1. `[]` The token mint. /// 2. `[writable]` The destination account. - /// 3. '[signer]' The source account's owner/delegate. + /// 3. `[signer]` The source account's owner/delegate. /// /// * Multisignature owner/delegate /// 0. `[writable]` The source account. - /// 1. '[]' The token mint. + /// 1. `[]` The token mint. /// 2. `[writable]` The destination account. - /// 3. '[]' The source account's multisignature owner/delegate. - /// 4. ..4+M '[signer]' M signer accounts. + /// 3. `[]` The source account's multisignature owner/delegate. + /// 4. ..4+M `[signer]` M signer accounts. Transfer2 { /// The amount of tokens to transfer. amount: u64, @@ -266,16 +266,16 @@ pub enum TokenInstruction { /// /// * Single owner /// 0. `[writable]` The source account. - /// 1. '[]' The token mint. + /// 1. `[]` The token mint. /// 2. `[]` The delegate. /// 3. `[signer]` The source account owner. /// /// * Multisignature owner /// 0. `[writable]` The source account. - /// 1. '[]' The token mint. + /// 1. `[]` The token mint. /// 2. `[]` The delegate. - /// 3. '[]' The source account's multisignature owner. - /// 4. ..4+M '[signer]' M signer accounts + /// 3. `[]` The source account's multisignature owner. + /// 4. ..4+M `[signer]` M signer accounts Approve2 { /// The amount of tokens the delegate is approved for. amount: u64, @@ -298,7 +298,7 @@ pub enum TokenInstruction { /// 0. `[writable]` The mint. /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M '[signer]' M signer accounts. + /// 3. ..3+M `[signer]` M signer accounts. MintTo2 { /// The amount of new tokens to mint. amount: u64, @@ -315,14 +315,14 @@ pub enum TokenInstruction { /// /// * Single owner/delegate /// 0. `[writable]` The account to burn from. - /// 1. '[writable]' The token mint. + /// 1. `[writable]` The token mint. /// 2. `[signer]` The account's owner/delegate. /// /// * Multisignature owner/delegate /// 0. `[writable]` The account to burn from. - /// 1. '[writable]' The token mint. + /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M '[signer]' M signer accounts. + /// 3. ..3+M `[signer]` M signer accounts. Burn2 { /// The amount of tokens to burn. amount: u64, @@ -570,7 +570,7 @@ impl AuthorityType { } } -/// Creates a 'InitializeMint' instruction. +/// Creates a `InitializeMint` instruction. pub fn initialize_mint( token_program_id: &Pubkey, mint_pubkey: &Pubkey, From b10fc15e1f7c046ff790e5ed1a5b0f5baa701966 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 28 Aug 2020 00:29:55 -0600 Subject: [PATCH 047/335] Bump spl-token to v2 (#352) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 2c8c9ca..9a8d17d 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "1.1.0" +version = "2.0.0" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 70edf1b866eeedffda5f2b0e8ea048552e48098f Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 27 Aug 2020 21:58:57 -0700 Subject: [PATCH 048/335] Move c header generation out of build.rs --- program/Cargo.toml | 3 - program/build.rs | 65 ------- program/inc/token.h | 418 +++++++------------------------------------- 3 files changed, 65 insertions(+), 421 deletions(-) delete mode 100644 program/build.rs diff --git a/program/Cargo.toml b/program/Cargo.toml index 9a8d17d..e0b2394 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -29,8 +29,5 @@ num_enum = "0.5.1" [dev-dependencies] rand = { version = "0.7.0"} -[build-dependencies] -cbindgen = "=0.14.2" - [lib] crate-type = ["cdylib", "lib"] diff --git a/program/build.rs b/program/build.rs deleted file mode 100644 index 4862075..0000000 --- a/program/build.rs +++ /dev/null @@ -1,65 +0,0 @@ -extern crate cbindgen; - -use std::env; - -fn main() { - println!("cargo:rerun-if-env-changed=SPL_CBINDGEN"); - println!("cargo:rerun-if-changed=inc/token.h"); - if std::path::Path::new("inc/token.h").exists() && env::var("SPL_CBINDGEN").is_err() { - return; - } - - println!("cargo:warning=Generating inc/token.h"); - let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let config = cbindgen::Config { - header: Some("/* Autogenerated SPL Token program C Bindings */".to_string()), - after_includes: Some(format!( - "{}{}{}", - format!( - "\n#define TOKEN_MAJOR_VERSION {}", - env!("CARGO_PKG_VERSION_MAJOR") - ), - format!( - "\n#define TOKEN_MINOR_VERSION {}", - env!("CARGO_PKG_VERSION_MINOR") - ), - format!( - "\n#define TOKEN_PATCH_VERSION {}", - env!("CARGO_PKG_VERSION_PATCH") - ) - )), - language: cbindgen::Language::C, - line_length: 80, - style: cbindgen::Style::Both, - tab_width: 4, - cpp_compat: true, - pragma_once: true, - enumeration: cbindgen::EnumConfig { - prefix_with_name: true, - ..cbindgen::EnumConfig::default() - }, - export: cbindgen::ExportConfig { - prefix: Some("Token_".to_string()), - include: vec![ - "TokenInstruction".to_string(), - "Mint".to_string(), - "Account".to_string(), - "Multisig".to_string(), - ], - exclude: vec!["DECIMALS".to_string()], - ..cbindgen::ExportConfig::default() - }, - parse: cbindgen::ParseConfig { - parse_deps: true, - include: Some(vec!["solana-sdk".to_string()]), - ..cbindgen::ParseConfig::default() - }, - ..cbindgen::Config::default() - }; - cbindgen::Builder::new() - .with_crate(crate_dir) - .with_config(config) - .generate() - .unwrap() - .write_to_file("inc/token.h"); -} diff --git a/program/inc/token.h b/program/inc/token.h index 32df44b..75f394b 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -7,10 +7,6 @@ #include #include -#define TOKEN_MAJOR_VERSION 1 -#define TOKEN_MINOR_VERSION 1 -#define TOKEN_PATCH_VERSION 0 - /** * Maximum number of multisignature signers (max N) */ @@ -21,89 +17,6 @@ */ #define Token_MIN_SIGNERS 1 -/** - * Account state. - */ -enum Token_AccountState -#ifdef __cplusplus - : uint8_t -#endif // __cplusplus - { - /** - * Account is not yet initialized - */ - Token_AccountState_Uninitialized, - /** - * Account is initialized; the account owner and/or delegate may perform permitted operations - * on this account - */ - Token_AccountState_Initialized, - /** - * Account has been frozen by the mint freeze authority. Neither the account owner nor - * the delegate are able to perform operations on this account. - */ - Token_AccountState_Frozen, -}; -#ifndef __cplusplus -typedef uint8_t Token_AccountState; -#endif // __cplusplus - -/** - * Specifies the authority type for SetAuthority instructions - */ -enum Token_AuthorityType -#ifdef __cplusplus - : uint8_t -#endif // __cplusplus - { - /** - * Authority to mint new tokens - */ - Token_AuthorityType_MintTokens, - /** - * Authority to freeze any account associated with the Mint - */ - Token_AuthorityType_FreezeAccount, - /** - * Holder of a given token account - */ - Token_AuthorityType_AccountHolder, - /** - * Authority to close a token account - */ - Token_AuthorityType_CloseAccount, -}; -#ifndef __cplusplus -typedef uint8_t Token_AuthorityType; -#endif // __cplusplus - -typedef uint8_t Token_Pubkey[32]; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_Pubkey_Tag { - /** - * No value - */ - Token_COption_Pubkey_None_Pubkey, - /** - * Some value `T` - */ - Token_COption_Pubkey_Some_Pubkey, -} Token_COption_Pubkey_Tag; - -typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { - Token_Pubkey _0; -} Token_COption_Pubkey_Token_Some_Body_Pubkey; - -typedef struct Token_COption_Pubkey { - Token_COption_Pubkey_Tag tag; - union { - Token_COption_Pubkey_Token_Some_Body_Pubkey some; - }; -} Token_COption_Pubkey; - /** * Instructions supported by the token program. */ @@ -118,15 +31,17 @@ typedef enum Token_TokenInstruction_Tag { * Accounts expected by this instruction: * * 0. `[writable]` The mint to initialize. - * 1. `[]` Rent sysvar + * 1. + * * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. + * * If supply is zero: `[]` The owner/multisignature of the mint. + * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if + * present then further minting is supported. * */ Token_TokenInstruction_InitializeMint, /** - * Initializes a new account to hold tokens. If this account is associated with the native - * mint then the token balance of the initialized account will be equal to the amount of SOL - * in the account. If this account is associated with another mint, that mint must be - * initialized before this command can succeed. + * Initializes a new account to hold tokens. If this account is associated with the native mint + * then the token balance of the initialized account will be equal to the amount of SOL in the account. * * The `InitializeAccount` instruction requires no signers and MUST be included within * the same Transaction as the system program's `CreateInstruction` that creates the account @@ -137,7 +52,6 @@ typedef enum Token_TokenInstruction_Tag { * 0. `[writable]` The account to initialize. * 1. `[]` The mint this account will be associated with. * 2. `[]` The new account's owner/multisignature. - * 3. `[]` Rent sysvar */ Token_TokenInstruction_InitializeAccount, /** @@ -154,8 +68,7 @@ typedef enum Token_TokenInstruction_Tag { * Accounts expected by this instruction: * * 0. `[writable]` The multisignature account to initialize. - * 1. `[]` Rent sysvar - * 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + * 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. */ Token_TokenInstruction_InitializeMultisig, /** @@ -180,7 +93,6 @@ typedef enum Token_TokenInstruction_Tag { /** * Approves a delegate. A delegate is given the authority over * tokens on behalf of the source account's owner. - * * Accounts expected by this instruction: * * * Single owner @@ -211,34 +123,36 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_Revoke, /** - * Sets a new authority of a mint or account. + * Sets a new owner of a mint or account. * * Accounts expected by this instruction: * - * * Single authority - * 0. `[writable]` The mint or account to change the authority of. - * 1. `[signer]` The current authority of the mint or account. + * * Single owner + * 0. `[writable]` The mint or account to change the owner of. + * 1. `[]` The new owner/delegate/multisignature. + * 2. `[signer]` The owner of the mint or account. * - * * Multisignature authority - * 0. `[writable]` The mint or account to change the authority of. - * 1. `[]` The mint's or account's multisignature authority. - * 2. ..2+M '[signer]' M signer accounts + * * Multisignature owner + * 0. `[writable]` The mint or account to change the owner of. + * 1. `[]` The new owner/delegate/multisignature. + * 2. `[]` The mint's or account's multisignature owner. + * 3. ..3+M '[signer]' M signer accounts */ - Token_TokenInstruction_SetAuthority, + Token_TokenInstruction_SetOwner, /** * Mints new tokens to an account. The native mint does not support minting. * * Accounts expected by this instruction: * - * * Single authority + * * Single owner * 0. `[writable]` The mint. * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's minting authority. + * 2. `[signer]` The mint's owner. * - * * Multisignature authority + * * Multisignature owner * 0. `[writable]` The mint. * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature mint-tokens authority. + * 2. `[]` The mint's multisignature owner. * 3. ..3+M '[signer]' M signer accounts. */ Token_TokenInstruction_MintTo, @@ -250,14 +164,12 @@ typedef enum Token_TokenInstruction_Tag { * * * Single owner/delegate * 0. `[writable]` The account to burn from. - * 1. '[writable]' The token mint. - * 2. `[signer]` The account's owner/delegate. + * 1. `[signer]` The account's owner/delegate. * * * Multisignature owner/delegate * 0. `[writable]` The account to burn from. - * 1. '[writable]' The token mint. - * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M '[signer]' M signer accounts. + * 1. `[]` The account's multisignature owner/delegate. + * 2. ..2+M '[signer]' M signer accounts. */ Token_TokenInstruction_Burn, /** @@ -278,145 +190,17 @@ typedef enum Token_TokenInstruction_Tag { * 3. ..3+M '[signer]' M signer accounts. */ Token_TokenInstruction_CloseAccount, - /** - * Freeze an Initialized account using the Mint's freeze_authority (if set). - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to freeze. - * 1. '[]' The token mint. - * 2. `[signer]` The mint freeze authority. - * - * * Multisignature owner - * 0. `[writable]` The account to freeze. - * 1. '[]' The token mint. - * 2. `[]` The mint's multisignature freeze authority. - * 3. ..3+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_FreezeAccount, - /** - * Thaw a Frozen account using the Mint's freeze_authority (if set). - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to freeze. - * 1. '[]' The token mint. - * 2. `[signer]` The mint freeze authority. - * - * * Multisignature owner - * 0. `[writable]` The account to freeze. - * 1. '[]' The token mint. - * 2. `[]` The mint's multisignature freeze authority. - * 3. ..3+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_ThawAccount, - /** - * Transfers tokens from one account to another either directly or via a delegate. If this - * account is associated with the native mint then equal amounts of SOL and Tokens will be - * transferred to the destination account. - * - * This instruction differs from Transfer in that the token mint and decimals value is - * asserted by the caller. This may be useful when creating transactions offline or within a - * hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The source account. - * 1. '[]' The token mint. - * 2. `[writable]` The destination account. - * 3. '[signer]' The source account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The source account. - * 1. '[]' The token mint. - * 2. `[writable]` The destination account. - * 3. '[]' The source account's multisignature owner/delegate. - * 4. ..4+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_Transfer2, - /** - * Approves a delegate. A delegate is given the authority over - * tokens on behalf of the source account's owner. - * - * This instruction differs from Approve in that the token mint and decimals value is asserted - * by the caller. This may be useful when creating transactions offline or within a hardware - * wallet. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. '[]' The token mint. - * 2. `[]` The delegate. - * 3. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. '[]' The token mint. - * 2. `[]` The delegate. - * 3. '[]' The source account's multisignature owner. - * 4. ..4+M '[signer]' M signer accounts - */ - Token_TokenInstruction_Approve2, - /** - * Mints new tokens to an account. The native mint does not support minting. - * - * This instruction differs from MintTo in that the decimals value is asserted by the - * caller. This may be useful when creating transactions offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's minting authority. - * - * * Multisignature authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature mint-tokens authority. - * 3. ..3+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_MintTo2, - /** - * Burns tokens by removing them from an account. `Burn2` does not support accounts - * associated with the native mint, use `CloseAccount` instead. - * - * This instruction differs from Burn in that the decimals value is asserted by the caller. - * This may be useful when creating transactions offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The account to burn from. - * 1. '[writable]' The token mint. - * 2. `[signer]` The account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The account to burn from. - * 1. '[writable]' The token mint. - * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M '[signer]' M signer accounts. - */ - Token_TokenInstruction_Burn2, } Token_TokenInstruction_Tag; typedef struct Token_TokenInstruction_Token_InitializeMint_Body { /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; - /** - * The authority/multisignature to mint tokens. + * Initial amount of tokens to mint. */ - Token_Pubkey mint_authority; + uint64_t amount; /** - * The freeze authority/multisignature of the mint. + * Number of base 10 digits to the right of the decimal place. */ - Token_COption_Pubkey freeze_authority; + uint8_t decimals; } Token_TokenInstruction_Token_InitializeMint_Body; typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { @@ -440,17 +224,6 @@ typedef struct Token_TokenInstruction_Token_Approve_Body { uint64_t amount; } Token_TokenInstruction_Token_Approve_Body; -typedef struct Token_TokenInstruction_Token_SetAuthority_Body { - /** - * The type of authority to update. - */ - Token_AuthorityType authority_type; - /** - * The new authority - */ - Token_COption_Pubkey new_authority; -} Token_TokenInstruction_Token_SetAuthority_Body; - typedef struct Token_TokenInstruction_Token_MintTo_Body { /** * The amount of new tokens to mint. @@ -465,50 +238,6 @@ typedef struct Token_TokenInstruction_Token_Burn_Body { uint64_t amount; } Token_TokenInstruction_Token_Burn_Body; -typedef struct Token_TokenInstruction_Token_Transfer2_Body { - /** - * The amount of tokens to transfer. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_Transfer2_Body; - -typedef struct Token_TokenInstruction_Token_Approve2_Body { - /** - * The amount of tokens the delegate is approved for. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_Approve2_Body; - -typedef struct Token_TokenInstruction_Token_MintTo2_Body { - /** - * The amount of new tokens to mint. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_MintTo2_Body; - -typedef struct Token_TokenInstruction_Token_Burn2_Body { - /** - * The amount of tokens to burn. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_Burn2_Body; - typedef struct Token_TokenInstruction { Token_TokenInstruction_Tag tag; union { @@ -516,30 +245,48 @@ typedef struct Token_TokenInstruction { Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; Token_TokenInstruction_Token_Transfer_Body transfer; Token_TokenInstruction_Token_Approve_Body approve; - Token_TokenInstruction_Token_SetAuthority_Body set_authority; Token_TokenInstruction_Token_MintTo_Body mint_to; Token_TokenInstruction_Token_Burn_Body burn; - Token_TokenInstruction_Token_Transfer2_Body transfer2; - Token_TokenInstruction_Token_Approve2_Body approve2; - Token_TokenInstruction_Token_MintTo2_Body mint_to2; - Token_TokenInstruction_Token_Burn2_Body burn2; }; } Token_TokenInstruction; +typedef uint8_t Token_Pubkey[32]; + /** - * Mint data. + * A C representation of Rust's `std::option::Option` */ -typedef struct Token_Mint { +typedef enum Token_COption_Pubkey_Tag { /** - * Optional authority used to mint new tokens. The mint authority may only be provided during - * mint creation. If no mint authority is present then the mint has a fixed supply and no - * further tokens may be minted. + * No value */ - Token_COption_Pubkey mint_authority; + Token_COption_Pubkey_None_Pubkey, /** - * Total supply of tokens. + * Some value `T` */ - uint64_t supply; + Token_COption_Pubkey_Some_Pubkey, +} Token_COption_Pubkey_Tag; + +typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { + Token_Pubkey _0; +} Token_COption_Pubkey_Token_Some_Body_Pubkey; + +typedef struct Token_COption_Pubkey { + Token_COption_Pubkey_Tag tag; + union { + Token_COption_Pubkey_Token_Some_Body_Pubkey some; + }; +} Token_COption_Pubkey; + +/** + * Mint data. + */ +typedef struct Token_Mint { + /** + * Optional owner, used to mint new tokens. The owner may only + * be provided during mint creation. If no owner is present then the mint + * has a fixed supply and no further tokens may be minted. + */ + Token_COption_Pubkey owner; /** * Number of base 10 digits to the right of the decimal place. */ @@ -548,37 +295,8 @@ typedef struct Token_Mint { * Is `true` if this structure has been initialized */ bool is_initialized; - /** - * Optional authority to freeze token accounts. - */ - Token_COption_Pubkey freeze_authority; } Token_Mint; -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_u64_Tag { - /** - * No value - */ - Token_COption_u64_None_u64, - /** - * Some value `T` - */ - Token_COption_u64_Some_u64, -} Token_COption_u64_Tag; - -typedef struct Token_COption_u64_Token_Some_Body_u64 { - uint64_t _0; -} Token_COption_u64_Token_Some_Body_u64; - -typedef struct Token_COption_u64 { - Token_COption_u64_Tag tag; - union { - Token_COption_u64_Token_Some_Body_u64 some; - }; -} Token_COption_u64; - /** * Account data. */ @@ -601,23 +319,17 @@ typedef struct Token_Account { */ Token_COption_Pubkey delegate; /** - * The account's state + * Is `true` if this structure has been initialized */ - Token_AccountState state; + bool is_initialized; /** - * If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account - * is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped - * SOL accounts do not drop below this threshold. + * Is this a native token */ - Token_COption_u64 is_native; + bool is_native; /** * The amount delegated */ uint64_t delegated_amount; - /** - * Optional authority to close the account. - */ - Token_COption_Pubkey close_authority; } Token_Account; /** From a6ef5bcea8f893b60d9bc3da1f26c1adb1fb27e6 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 27 Aug 2020 22:48:31 -0700 Subject: [PATCH 049/335] Update token.h --- program/inc/token.h | 436 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 360 insertions(+), 76 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index 75f394b..3a156fa 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -17,6 +17,89 @@ */ #define Token_MIN_SIGNERS 1 +/** + * Account state. + */ +enum Token_AccountState +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + /** + * Account is not yet initialized + */ + Token_AccountState_Uninitialized, + /** + * Account is initialized; the account owner and/or delegate may perform permitted operations + * on this account + */ + Token_AccountState_Initialized, + /** + * Account has been frozen by the mint freeze authority. Neither the account owner nor + * the delegate are able to perform operations on this account. + */ + Token_AccountState_Frozen, +}; +#ifndef __cplusplus +typedef uint8_t Token_AccountState; +#endif // __cplusplus + +/** + * Specifies the authority type for SetAuthority instructions + */ +enum Token_AuthorityType +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + /** + * Authority to mint new tokens + */ + Token_AuthorityType_MintTokens, + /** + * Authority to freeze any account associated with the Mint + */ + Token_AuthorityType_FreezeAccount, + /** + * Holder of a given token account + */ + Token_AuthorityType_AccountHolder, + /** + * Authority to close a token account + */ + Token_AuthorityType_CloseAccount, +}; +#ifndef __cplusplus +typedef uint8_t Token_AuthorityType; +#endif // __cplusplus + +typedef uint8_t Token_Pubkey[32]; + +/** + * A C representation of Rust's `std::option::Option` + */ +typedef enum Token_COption_Pubkey_Tag { + /** + * No value + */ + Token_COption_Pubkey_None_Pubkey, + /** + * Some value `T` + */ + Token_COption_Pubkey_Some_Pubkey, +} Token_COption_Pubkey_Tag; + +typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { + Token_Pubkey _0; +} Token_COption_Pubkey_Token_Some_Body_Pubkey; + +typedef struct Token_COption_Pubkey { + Token_COption_Pubkey_Tag tag; + union { + Token_COption_Pubkey_Token_Some_Body_Pubkey some; + }; +} Token_COption_Pubkey; + /** * Instructions supported by the token program. */ @@ -31,17 +114,15 @@ typedef enum Token_TokenInstruction_Tag { * Accounts expected by this instruction: * * 0. `[writable]` The mint to initialize. - * 1. - * * If supply is non-zero: `[writable]` The account to hold all the newly minted tokens. - * * If supply is zero: `[]` The owner/multisignature of the mint. - * 2. `[]` (optional) The owner/multisignature of the mint if supply is non-zero, if - * present then further minting is supported. + * 1. `[]` Rent sysvar * */ Token_TokenInstruction_InitializeMint, /** - * Initializes a new account to hold tokens. If this account is associated with the native mint - * then the token balance of the initialized account will be equal to the amount of SOL in the account. + * Initializes a new account to hold tokens. If this account is associated with the native + * mint then the token balance of the initialized account will be equal to the amount of SOL + * in the account. If this account is associated with another mint, that mint must be + * initialized before this command can succeed. * * The `InitializeAccount` instruction requires no signers and MUST be included within * the same Transaction as the system program's `CreateInstruction` that creates the account @@ -52,6 +133,7 @@ typedef enum Token_TokenInstruction_Tag { * 0. `[writable]` The account to initialize. * 1. `[]` The mint this account will be associated with. * 2. `[]` The new account's owner/multisignature. + * 3. `[]` Rent sysvar */ Token_TokenInstruction_InitializeAccount, /** @@ -68,7 +150,8 @@ typedef enum Token_TokenInstruction_Tag { * Accounts expected by this instruction: * * 0. `[writable]` The multisignature account to initialize. - * 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + * 1. `[]` Rent sysvar + * 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. */ Token_TokenInstruction_InitializeMultisig, /** @@ -81,18 +164,19 @@ typedef enum Token_TokenInstruction_Tag { * * Single owner/delegate * 0. `[writable]` The source account. * 1. `[writable]` The destination account. - * 2. '[signer]' The source account's owner/delegate. + * 2. `[signer]` The source account's owner/delegate. * * * Multisignature owner/delegate * 0. `[writable]` The source account. * 1. `[writable]` The destination account. - * 2. '[]' The source account's multisignature owner/delegate. - * 3. ..3+M '[signer]' M signer accounts. + * 2. `[]` The source account's multisignature owner/delegate. + * 3. ..3+M `[signer]` M signer accounts. */ Token_TokenInstruction_Transfer, /** * Approves a delegate. A delegate is given the authority over * tokens on behalf of the source account's owner. + * * Accounts expected by this instruction: * * * Single owner @@ -103,8 +187,8 @@ typedef enum Token_TokenInstruction_Tag { * * Multisignature owner * 0. `[writable]` The source account. * 1. `[]` The delegate. - * 2. '[]' The source account's multisignature owner. - * 3. ..3+M '[signer]' M signer accounts + * 2. `[]` The source account's multisignature owner. + * 3. ..3+M `[signer]` M signer accounts */ Token_TokenInstruction_Approve, /** @@ -118,42 +202,40 @@ typedef enum Token_TokenInstruction_Tag { * * * Multisignature owner * 0. `[writable]` The source account. - * 1. '[]' The source account's multisignature owner. - * 2. ..2+M '[signer]' M signer accounts + * 1. `[]` The source account's multisignature owner. + * 2. ..2+M `[signer]` M signer accounts */ Token_TokenInstruction_Revoke, /** - * Sets a new owner of a mint or account. + * Sets a new authority of a mint or account. * * Accounts expected by this instruction: * - * * Single owner - * 0. `[writable]` The mint or account to change the owner of. - * 1. `[]` The new owner/delegate/multisignature. - * 2. `[signer]` The owner of the mint or account. + * * Single authority + * 0. `[writable]` The mint or account to change the authority of. + * 1. `[signer]` The current authority of the mint or account. * - * * Multisignature owner - * 0. `[writable]` The mint or account to change the owner of. - * 1. `[]` The new owner/delegate/multisignature. - * 2. `[]` The mint's or account's multisignature owner. - * 3. ..3+M '[signer]' M signer accounts + * * Multisignature authority + * 0. `[writable]` The mint or account to change the authority of. + * 1. `[]` The mint's or account's multisignature authority. + * 2. ..2+M `[signer]` M signer accounts */ - Token_TokenInstruction_SetOwner, + Token_TokenInstruction_SetAuthority, /** * Mints new tokens to an account. The native mint does not support minting. * * Accounts expected by this instruction: * - * * Single owner + * * Single authority * 0. `[writable]` The mint. * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's owner. + * 2. `[signer]` The mint's minting authority. * - * * Multisignature owner + * * Multisignature authority * 0. `[writable]` The mint. * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature owner. - * 3. ..3+M '[signer]' M signer accounts. + * 2. `[]` The mint's multisignature mint-tokens authority. + * 3. ..3+M `[signer]` M signer accounts. */ Token_TokenInstruction_MintTo, /** @@ -164,12 +246,14 @@ typedef enum Token_TokenInstruction_Tag { * * * Single owner/delegate * 0. `[writable]` The account to burn from. - * 1. `[signer]` The account's owner/delegate. + * 1. `[writable]` The token mint. + * 2. `[signer]` The account's owner/delegate. * * * Multisignature owner/delegate * 0. `[writable]` The account to burn from. - * 1. `[]` The account's multisignature owner/delegate. - * 2. ..2+M '[signer]' M signer accounts. + * 1. '[writable]' The token mint. + * 2. `[]` The account's multisignature owner/delegate. + * 3. ..3+M '[signer]' M signer accounts. */ Token_TokenInstruction_Burn, /** @@ -180,27 +264,155 @@ typedef enum Token_TokenInstruction_Tag { * * * Single owner * 0. `[writable]` The account to close. - * 1. '[writable]' The destination account. + * 1. `[writable]` The destination account. * 2. `[signer]` The account's owner. * * * Multisignature owner * 0. `[writable]` The account to close. - * 1. '[writable]' The destination account. + * 1. `[writable]` The destination account. * 2. `[]` The account's multisignature owner. - * 3. ..3+M '[signer]' M signer accounts. + * 3. ..3+M `[signer]` M signer accounts. */ Token_TokenInstruction_CloseAccount, + /** + * Freeze an Initialized account using the Mint's freeze_authority (if set). + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The account to freeze. + * 1. `[]` The token mint. + * 2. `[signer]` The mint freeze authority. + * + * * Multisignature owner + * 0. `[writable]` The account to freeze. + * 1. `[]` The token mint. + * 2. `[]` The mint's multisignature freeze authority. + * 3. ..3+M `[signer]` M signer accounts. + */ + Token_TokenInstruction_FreezeAccount, + /** + * Thaw a Frozen account using the Mint's freeze_authority (if set). + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The account to freeze. + * 1. `[]` The token mint. + * 2. `[signer]` The mint freeze authority. + * + * * Multisignature owner + * 0. `[writable]` The account to freeze. + * 1. `[]` The token mint. + * 2. `[]` The mint's multisignature freeze authority. + * 3. ..3+M `[signer]` M signer accounts. + */ + Token_TokenInstruction_ThawAccount, + /** + * Transfers tokens from one account to another either directly or via a delegate. If this + * account is associated with the native mint then equal amounts of SOL and Tokens will be + * transferred to the destination account. + * + * This instruction differs from Transfer in that the token mint and decimals value is + * asserted by the caller. This may be useful when creating transactions offline or within a + * hardware wallet. + * + * Accounts expected by this instruction: + * + * * Single owner/delegate + * 0. `[writable]` The source account. + * 1. `[]` The token mint. + * 2. `[writable]` The destination account. + * 3. `[signer]` The source account's owner/delegate. + * + * * Multisignature owner/delegate + * 0. `[writable]` The source account. + * 1. `[]` The token mint. + * 2. `[writable]` The destination account. + * 3. `[]` The source account's multisignature owner/delegate. + * 4. ..4+M `[signer]` M signer accounts. + */ + Token_TokenInstruction_Transfer2, + /** + * Approves a delegate. A delegate is given the authority over + * tokens on behalf of the source account's owner. + * + * This instruction differs from Approve in that the token mint and decimals value is asserted + * by the caller. This may be useful when creating transactions offline or within a hardware + * wallet. + * + * Accounts expected by this instruction: + * + * * Single owner + * 0. `[writable]` The source account. + * 1. `[]` The token mint. + * 2. `[]` The delegate. + * 3. `[signer]` The source account owner. + * + * * Multisignature owner + * 0. `[writable]` The source account. + * 1. `[]` The token mint. + * 2. `[]` The delegate. + * 3. `[]` The source account's multisignature owner. + * 4. ..4+M `[signer]` M signer accounts + */ + Token_TokenInstruction_Approve2, + /** + * Mints new tokens to an account. The native mint does not support minting. + * + * This instruction differs from MintTo in that the decimals value is asserted by the + * caller. This may be useful when creating transactions offline or within a hardware wallet. + * + * Accounts expected by this instruction: + * + * * Single authority + * 0. `[writable]` The mint. + * 1. `[writable]` The account to mint tokens to. + * 2. `[signer]` The mint's minting authority. + * + * * Multisignature authority + * 0. `[writable]` The mint. + * 1. `[writable]` The account to mint tokens to. + * 2. `[]` The mint's multisignature mint-tokens authority. + * 3. ..3+M `[signer]` M signer accounts. + */ + Token_TokenInstruction_MintTo2, + /** + * Burns tokens by removing them from an account. `Burn2` does not support accounts + * associated with the native mint, use `CloseAccount` instead. + * + * This instruction differs from Burn in that the decimals value is asserted by the caller. + * This may be useful when creating transactions offline or within a hardware wallet. + * + * Accounts expected by this instruction: + * + * * Single owner/delegate + * 0. `[writable]` The account to burn from. + * 1. `[writable]` The token mint. + * 2. `[signer]` The account's owner/delegate. + * + * * Multisignature owner/delegate + * 0. `[writable]` The account to burn from. + * 1. `[writable]` The token mint. + * 2. `[]` The account's multisignature owner/delegate. + * 3. ..3+M `[signer]` M signer accounts. + */ + Token_TokenInstruction_Burn2, } Token_TokenInstruction_Tag; typedef struct Token_TokenInstruction_Token_InitializeMint_Body { - /** - * Initial amount of tokens to mint. - */ - uint64_t amount; /** * Number of base 10 digits to the right of the decimal place. */ uint8_t decimals; + /** + * The authority/multisignature to mint tokens. + */ + Token_Pubkey mint_authority; + /** + * The freeze authority/multisignature of the mint. + */ + Token_COption_Pubkey freeze_authority; } Token_TokenInstruction_Token_InitializeMint_Body; typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { @@ -224,6 +436,17 @@ typedef struct Token_TokenInstruction_Token_Approve_Body { uint64_t amount; } Token_TokenInstruction_Token_Approve_Body; +typedef struct Token_TokenInstruction_Token_SetAuthority_Body { + /** + * The type of authority to update. + */ + Token_AuthorityType authority_type; + /** + * The new authority + */ + Token_COption_Pubkey new_authority; +} Token_TokenInstruction_Token_SetAuthority_Body; + typedef struct Token_TokenInstruction_Token_MintTo_Body { /** * The amount of new tokens to mint. @@ -238,6 +461,50 @@ typedef struct Token_TokenInstruction_Token_Burn_Body { uint64_t amount; } Token_TokenInstruction_Token_Burn_Body; +typedef struct Token_TokenInstruction_Token_Transfer2_Body { + /** + * The amount of tokens to transfer. + */ + uint64_t amount; + /** + * Expected number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_Transfer2_Body; + +typedef struct Token_TokenInstruction_Token_Approve2_Body { + /** + * The amount of tokens the delegate is approved for. + */ + uint64_t amount; + /** + * Expected number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_Approve2_Body; + +typedef struct Token_TokenInstruction_Token_MintTo2_Body { + /** + * The amount of new tokens to mint. + */ + uint64_t amount; + /** + * Expected number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_MintTo2_Body; + +typedef struct Token_TokenInstruction_Token_Burn2_Body { + /** + * The amount of tokens to burn. + */ + uint64_t amount; + /** + * Expected number of base 10 digits to the right of the decimal place. + */ + uint8_t decimals; +} Token_TokenInstruction_Token_Burn2_Body; + typedef struct Token_TokenInstruction { Token_TokenInstruction_Tag tag; union { @@ -245,48 +512,30 @@ typedef struct Token_TokenInstruction { Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; Token_TokenInstruction_Token_Transfer_Body transfer; Token_TokenInstruction_Token_Approve_Body approve; + Token_TokenInstruction_Token_SetAuthority_Body set_authority; Token_TokenInstruction_Token_MintTo_Body mint_to; Token_TokenInstruction_Token_Burn_Body burn; + Token_TokenInstruction_Token_Transfer2_Body transfer2; + Token_TokenInstruction_Token_Approve2_Body approve2; + Token_TokenInstruction_Token_MintTo2_Body mint_to2; + Token_TokenInstruction_Token_Burn2_Body burn2; }; } Token_TokenInstruction; -typedef uint8_t Token_Pubkey[32]; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_Pubkey_Tag { - /** - * No value - */ - Token_COption_Pubkey_None_Pubkey, - /** - * Some value `T` - */ - Token_COption_Pubkey_Some_Pubkey, -} Token_COption_Pubkey_Tag; - -typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { - Token_Pubkey _0; -} Token_COption_Pubkey_Token_Some_Body_Pubkey; - -typedef struct Token_COption_Pubkey { - Token_COption_Pubkey_Tag tag; - union { - Token_COption_Pubkey_Token_Some_Body_Pubkey some; - }; -} Token_COption_Pubkey; - /** * Mint data. */ typedef struct Token_Mint { /** - * Optional owner, used to mint new tokens. The owner may only - * be provided during mint creation. If no owner is present then the mint - * has a fixed supply and no further tokens may be minted. + * Optional authority used to mint new tokens. The mint authority may only be provided during + * mint creation. If no mint authority is present then the mint has a fixed supply and no + * further tokens may be minted. + */ + Token_COption_Pubkey mint_authority; + /** + * Total supply of tokens. */ - Token_COption_Pubkey owner; + uint64_t supply; /** * Number of base 10 digits to the right of the decimal place. */ @@ -295,8 +544,37 @@ typedef struct Token_Mint { * Is `true` if this structure has been initialized */ bool is_initialized; + /** + * Optional authority to freeze token accounts. + */ + Token_COption_Pubkey freeze_authority; } Token_Mint; +/** + * A C representation of Rust's `std::option::Option` + */ +typedef enum Token_COption_u64_Tag { + /** + * No value + */ + Token_COption_u64_None_u64, + /** + * Some value `T` + */ + Token_COption_u64_Some_u64, +} Token_COption_u64_Tag; + +typedef struct Token_COption_u64_Token_Some_Body_u64 { + uint64_t _0; +} Token_COption_u64_Token_Some_Body_u64; + +typedef struct Token_COption_u64 { + Token_COption_u64_Tag tag; + union { + Token_COption_u64_Token_Some_Body_u64 some; + }; +} Token_COption_u64; + /** * Account data. */ @@ -319,17 +597,23 @@ typedef struct Token_Account { */ Token_COption_Pubkey delegate; /** - * Is `true` if this structure has been initialized + * The account's state */ - bool is_initialized; + Token_AccountState state; /** - * Is this a native token + * If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account + * is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped + * SOL accounts do not drop below this threshold. */ - bool is_native; + Token_COption_u64 is_native; /** * The amount delegated */ uint64_t delegated_amount; + /** + * Optional authority to close the account. + */ + Token_COption_Pubkey close_authority; } Token_Account; /** From 1e2bf3a22e1f0d7177a745048b34f802ebc8e116 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Fri, 28 Aug 2020 10:12:05 -0600 Subject: [PATCH 050/335] Token nits (#353) --- program/src/error.rs | 2 +- program/src/instruction.rs | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/program/src/error.rs b/program/src/error.rs index a69e57e..32cd9d2 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -26,7 +26,7 @@ pub enum TokenError { #[error("Fixed supply")] FixedSupply, /// The account cannot be initialized because it is already being used. - #[error("AlreadyInUse")] + #[error("Already in use")] AlreadyInUse, /// Invalid number of provided signers. #[error("Invalid number of provided signers")] diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 5052237..4daeee4 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -669,7 +669,7 @@ pub fn transfer( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -698,7 +698,7 @@ pub fn approve( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -718,13 +718,13 @@ pub fn revoke( let data = TokenInstruction::Revoke.pack(); let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); - accounts.push(AccountMeta::new_readonly(*source_pubkey, false)); + accounts.push(AccountMeta::new(*source_pubkey, false)); accounts.push(AccountMeta::new_readonly( *owner_pubkey, signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -757,7 +757,7 @@ pub fn set_authority( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -786,7 +786,7 @@ pub fn mint_to( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -815,7 +815,7 @@ pub fn burn( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -843,7 +843,7 @@ pub fn close_account( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -871,7 +871,7 @@ pub fn freeze_account( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -899,7 +899,7 @@ pub fn thaw_account( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -932,7 +932,7 @@ pub fn transfer2( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -965,7 +965,7 @@ pub fn approve2( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -995,7 +995,7 @@ pub fn mint_to2( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { @@ -1025,7 +1025,7 @@ pub fn burn2( signer_pubkeys.is_empty(), )); for signer_pubkey in signer_pubkeys.iter() { - accounts.push(AccountMeta::new(**signer_pubkey, true)); + accounts.push(AccountMeta::new_readonly(**signer_pubkey, true)); } Ok(Instruction { From f6c6a23cd84b5abe949c3704cadb26326a2f7741 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 28 Aug 2020 12:11:57 -0600 Subject: [PATCH 051/335] s/AccountHolder/AccountOwner (#356) --- program/inc/token.h | 4 ++-- program/src/instruction.rs | 8 ++++---- program/src/processor.rs | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index 3a156fa..954d841 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -61,9 +61,9 @@ enum Token_AuthorityType */ Token_AuthorityType_FreezeAccount, /** - * Holder of a given token account + * Owner of a given token account */ - Token_AuthorityType_AccountHolder, + Token_AuthorityType_AccountOwner, /** * Authority to close a token account */ diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 4daeee4..d51c8dd 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -543,8 +543,8 @@ pub enum AuthorityType { MintTokens, /// Authority to freeze any account associated with the Mint FreezeAccount, - /// Holder of a given token account - AccountHolder, + /// Owner of a given token account + AccountOwner, /// Authority to close a token account CloseAccount, } @@ -554,7 +554,7 @@ impl AuthorityType { match self { AuthorityType::MintTokens => 0, AuthorityType::FreezeAccount => 1, - AuthorityType::AccountHolder => 2, + AuthorityType::AccountOwner => 2, AuthorityType::CloseAccount => 3, } } @@ -563,7 +563,7 @@ impl AuthorityType { match index { 0 => Ok(AuthorityType::MintTokens), 1 => Ok(AuthorityType::FreezeAccount), - 2 => Ok(AuthorityType::AccountHolder), + 2 => Ok(AuthorityType::AccountOwner), 3 => Ok(AuthorityType::CloseAccount), _ => Err(TokenError::InvalidInstruction.into()), } diff --git a/program/src/processor.rs b/program/src/processor.rs index d2f647e..41373e1 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -342,7 +342,7 @@ impl Processor { } match authority_type { - AuthorityType::AccountHolder => { + AuthorityType::AccountOwner => { Self::validate_owner( program_id, &account.owner, @@ -1795,7 +1795,7 @@ mod tests { &program_id, &account_key, Some(&owner2_key), - AuthorityType::AccountHolder, + AuthorityType::AccountOwner, &owner_key, &[] ) @@ -1836,7 +1836,7 @@ mod tests { &program_id, &account_key, Some(&owner_key), - AuthorityType::AccountHolder, + AuthorityType::AccountOwner, &owner2_key, &[] ) @@ -1850,7 +1850,7 @@ mod tests { &program_id, &account_key, Some(&owner2_key), - AuthorityType::AccountHolder, + AuthorityType::AccountOwner, &owner_key, &[], ) @@ -1886,7 +1886,7 @@ mod tests { &program_id, &account_key, None, - AuthorityType::AccountHolder, + AuthorityType::AccountOwner, &owner_key, &[], ) @@ -1901,7 +1901,7 @@ mod tests { &program_id, &account_key, Some(&owner2_key), - AuthorityType::AccountHolder, + AuthorityType::AccountOwner, &owner_key, &[], ) @@ -2928,7 +2928,7 @@ mod tests { &program_id, &account_key, Some(&owner_key), - AuthorityType::AccountHolder, + AuthorityType::AccountOwner, &multisig_key, &[&signer_keys[0]], ) @@ -3858,7 +3858,7 @@ mod tests { &program_id, &account_key, Some(&new_owner_key), - AuthorityType::AccountHolder, + AuthorityType::AccountOwner, &owner_key, &[] ) From c3bb55e88ae19dbb79be01099b8df33a09fe4f22 Mon Sep 17 00:00:00 2001 From: Jack May Date: Fri, 28 Aug 2020 11:12:12 -0700 Subject: [PATCH 052/335] Remove last unsafes (#354) --- program/src/lib.rs | 1 + program/src/option.rs | 27 ++------------------------- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/program/src/lib.rs b/program/src/lib.rs index cb58c52..2addcd2 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -1,4 +1,5 @@ #![deny(missing_docs)] +#![forbid(unsafe_code)] //! An ERC20-like Token program for the Solana blockchain diff --git a/program/src/option.rs b/program/src/option.rs index 677408b..01ba5df 100644 --- a/program/src/option.rs +++ b/program/src/option.rs @@ -4,9 +4,8 @@ //! This implementation mostly matches `std::option` except iterators since the iteration //! trait requires returning `std::option::Option` -use std::pin::Pin; use std::{ - convert, hint, mem, + convert, mem, ops::{Deref, DerefMut}, }; @@ -151,28 +150,6 @@ impl COption { } } - /// Converts from [`Pin`]`<&COption>` to `COption<`[`Pin`]`<&T>>`. - /// - /// [`Pin`]: ../pin/struct.Pin.html - #[inline] - #[allow(clippy::wrong_self_convention)] - pub fn as_pin_ref(self: Pin<&Self>) -> COption> { - unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } - } - - /// Converts from [`Pin`]`<&mut COption>` to `COption<`[`Pin`]`<&mut T>>`. - /// - /// [`Pin`]: ../pin/struct.Pin.html - #[inline] - #[allow(clippy::wrong_self_convention)] - pub fn as_pin_mut(self: Pin<&mut Self>) -> COption> { - unsafe { - Pin::get_unchecked_mut(self) - .as_mut() - .map(|x| Pin::new_unchecked(x)) - } - } - ///////////////////////////////////////////////////////////////////////// // Getting to contained values ///////////////////////////////////////////////////////////////////////// @@ -645,7 +622,7 @@ impl COption { match *self { COption::Some(ref mut v) => v, - COption::None => unsafe { hint::unreachable_unchecked() }, + COption::None => unreachable!(), } } From 057519a286f1b485440ee620e6040e398234c4b6 Mon Sep 17 00:00:00 2001 From: Jack May Date: Fri, 28 Aug 2020 12:03:10 -0700 Subject: [PATCH 053/335] Don't repack if not needed (#355) --- program/src/pack.rs | 62 ++++++++++++++++++++----------------- program/src/processor.rs | 66 +++++++++++++++++----------------------- 2 files changed, 62 insertions(+), 66 deletions(-) diff --git a/program/src/pack.rs b/program/src/pack.rs index bf6a205..2650420 100644 --- a/program/src/pack.rs +++ b/program/src/pack.rs @@ -21,6 +21,28 @@ pub trait Pack: Sealed { #[doc(hidden)] fn unpack_from_slice(src: &[u8]) -> Result; + /// Unpack from slice and check if initialized + fn unpack(input: &[u8]) -> Result + where + Self: IsInitialized, + { + let value = Self::unpack_unchecked(input)?; + if value.is_initialized() { + Ok(value) + } else { + Err(TokenError::UninitializedState.into()) + } + } + + /// Unpack from slice without checking if initialized + fn unpack_unchecked(input: &[u8]) -> Result { + if input.len() < Self::LEN { + println!("ilen {:?} tlen {:?}", input.len(), Self::LEN); + return Err(ProgramError::InvalidAccountData); + } + Ok(Self::unpack_from_slice(input)?) + } + /// Borrow `Self` from `input` for the duration of the call to `f`, but first check that `Self` /// is initialized #[inline(never)] @@ -29,9 +51,9 @@ pub trait Pack: Sealed { F: FnMut(&mut Self) -> Result, Self: IsInitialized, { - let mut t = unpack(input)?; + let mut t = Self::unpack(input)?; let u = f(&mut t)?; - pack(t, input)?; + Self::pack(t, input)?; Ok(u) } @@ -42,35 +64,19 @@ pub trait Pack: Sealed { where F: FnMut(&mut Self) -> Result, { - let mut t = unpack_unchecked(input)?; + let mut t = Self::unpack_unchecked(input)?; let u = f(&mut t)?; - pack(t, input)?; + Self::pack(t, input)?; Ok(u) } -} - -fn pack(src: T, dst: &mut [u8]) -> Result<(), ProgramError> { - if dst.len() < T::LEN { - println!("dlen {:?} tlen {:?}", dst.len(), T::LEN); - return Err(ProgramError::InvalidAccountData); - } - src.pack_into_slice(dst); - Ok(()) -} - -fn unpack(input: &[u8]) -> Result { - let value: T = unpack_unchecked(input)?; - if value.is_initialized() { - Ok(value) - } else { - Err(TokenError::UninitializedState.into()) - } -} -fn unpack_unchecked(input: &[u8]) -> Result { - if input.len() < T::LEN { - println!("ilen {:?} tlen {:?}", input.len(), T::LEN); - return Err(ProgramError::InvalidAccountData); + /// Pack into slice + fn pack(src: Self, dst: &mut [u8]) -> Result<(), ProgramError> { + if dst.len() < Self::LEN { + println!("dlen {:?} tlen {:?}", dst.len(), Self::LEN); + return Err(ProgramError::InvalidAccountData); + } + src.pack_into_slice(dst); + Ok(()) } - Ok(T::unpack_from_slice(input)?) } diff --git a/program/src/processor.rs b/program/src/processor.rs index 41373e1..9ab174e 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -75,8 +75,7 @@ impl Processor { } if *mint_info.key != crate::native_mint::id() { - let mut mint_info_data = mint_info.data.borrow_mut(); - Mint::unpack_mut(&mut mint_info_data, &mut |_| Ok(())) + let _ = Mint::unpack(&mint_info.data.borrow_mut()) .map_err(|_| Into::::into(TokenError::InvalidMint))?; } @@ -177,18 +176,15 @@ impl Processor { return Err(TokenError::AccountFrozen.into()); } - if let Some((mint_account_info, expected_decimals)) = expected_mint_info { - if source_account.mint != *mint_account_info.key { + if let Some((mint_info, expected_decimals)) = expected_mint_info { + if source_account.mint != *mint_info.key { return Err(TokenError::MintMismatch.into()); } - let mut mint_info_data = mint_account_info.data.borrow_mut(); - Mint::unpack_mut(&mut mint_info_data, &mut |mint: &mut Mint| { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - Ok(()) - })?; + let mint = Mint::unpack(&mint_info.data.borrow_mut())?; + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } } match source_account.delegate { @@ -268,18 +264,15 @@ impl Processor { return Err(TokenError::AccountFrozen.into()); } - if let Some((mint_account_info, expected_decimals)) = expected_mint_info { - if source_account.mint != *mint_account_info.key { + if let Some((mint_info, expected_decimals)) = expected_mint_info { + if source_account.mint != *mint_info.key { return Err(TokenError::MintMismatch.into()); } - let mut mint_info_data = mint_account_info.data.borrow_mut(); - Mint::unpack_mut(&mut mint_info_data, &mut |mint: &mut Mint| { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - Ok(()) - })?; + let mint = Mint::unpack(&mint_info.data.borrow_mut())?; + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } } Self::validate_owner( @@ -442,8 +435,8 @@ impl Processor { return Err(TokenError::MintMismatch.into()); } - let mut mint_info_data = mint_info.data.borrow_mut(); - Mint::unpack_mut(&mut mint_info_data, &mut |mint: &mut Mint| { + let mut mint_data = mint_info.data.borrow_mut(); + Mint::unpack_mut(&mut mint_data, &mut |mint: &mut Mint| { if let Some(expected_decimals) = expected_decimals { if expected_decimals != mint.decimals { return Err(TokenError::MintDecimalsMismatch.into()); @@ -612,19 +605,16 @@ impl Processor { return Err(TokenError::InvalidState.into()); } - let mut mint_data = mint_info.data.borrow_mut(); - Mint::unpack_mut( - &mut mint_data, - &mut |mint: &mut Mint| match mint.freeze_authority { - COption::Some(authority) => Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - ), - COption::None => Err(TokenError::MintCannotFreeze.into()), - }, - )?; + let mint = Mint::unpack(&mint_info.data.borrow_mut())?; + match mint.freeze_authority { + COption::Some(authority) => Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + ), + COption::None => Err(TokenError::MintCannotFreeze.into()), + }?; source_account.state = if freeze { AccountState::Frozen @@ -1497,7 +1487,7 @@ mod tests { vec![&mut mint_account, &mut account_account, &mut owner_account], ) .unwrap(); - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |_| Ok(())).unwrap(); + let _ = Mint::unpack(&mut mint_account.data).unwrap(); Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { assert_eq!(account.amount, 42); Ok(()) @@ -1522,7 +1512,7 @@ mod tests { ) ); - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |_| Ok(())).unwrap(); + let _ = Mint::unpack(&mut mint_account.data).unwrap(); Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { assert_eq!(account.amount, 42); Ok(()) @@ -1544,7 +1534,7 @@ mod tests { vec![&mut mint_account, &mut account_account, &mut owner_account], ) .unwrap(); - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |_| Ok(())).unwrap(); + let _ = Mint::unpack(&mut mint_account.data).unwrap(); Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { assert_eq!(account.amount, 84); Ok(()) From 6127d3fcb80289b9ebaa632ec827a52ad4db2fd2 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 28 Aug 2020 13:34:29 -0600 Subject: [PATCH 054/335] Bump version (#357) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index e0b2394..45f7856 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "2.0.0" +version = "2.0.1" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 1d3b1950fdec62d2c55b6967195d6c93ef8192d3 Mon Sep 17 00:00:00 2001 From: Jack May Date: Fri, 28 Aug 2020 16:21:57 -0700 Subject: [PATCH 055/335] Fix account size comparisons (#359) --- program/src/pack.rs | 11 +- program/src/processor.rs | 395 +++++++++++++++++++++++++++++---------- program/src/state.rs | 6 +- 3 files changed, 306 insertions(+), 106 deletions(-) diff --git a/program/src/pack.rs b/program/src/pack.rs index 2650420..7a86cb9 100644 --- a/program/src/pack.rs +++ b/program/src/pack.rs @@ -21,6 +21,11 @@ pub trait Pack: Sealed { #[doc(hidden)] fn unpack_from_slice(src: &[u8]) -> Result; + /// Get the packed length + fn get_packed_len() -> usize { + Self::LEN + } + /// Unpack from slice and check if initialized fn unpack(input: &[u8]) -> Result where @@ -36,8 +41,7 @@ pub trait Pack: Sealed { /// Unpack from slice without checking if initialized fn unpack_unchecked(input: &[u8]) -> Result { - if input.len() < Self::LEN { - println!("ilen {:?} tlen {:?}", input.len(), Self::LEN); + if input.len() != Self::LEN { return Err(ProgramError::InvalidAccountData); } Ok(Self::unpack_from_slice(input)?) @@ -72,8 +76,7 @@ pub trait Pack: Sealed { /// Pack into slice fn pack(src: Self, dst: &mut [u8]) -> Result<(), ProgramError> { - if dst.len() < Self::LEN { - println!("dlen {:?} tlen {:?}", dst.len(), Self::LEN); + if dst.len() != Self::LEN { return Err(ProgramError::InvalidAccountData); } src.pack_into_slice(dst); diff --git a/program/src/processor.rs b/program/src/processor.rs index 9ab174e..32d3f7e 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -19,7 +19,6 @@ use solana_sdk::{ pubkey::Pubkey, sysvar::{rent::Rent, Sysvar}, }; -use std::mem::size_of; /// Program state handler. pub struct Processor {} @@ -327,7 +326,7 @@ impl Processor { let account_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; - if account_info.data_len() == size_of::() { + if account_info.data_len() == Account::get_packed_len() { let mut account_data = account_info.data.borrow_mut(); Account::unpack_mut(&mut account_data, &mut |account: &mut Account| { if account.is_frozen() { @@ -365,7 +364,7 @@ impl Processor { } Ok(()) })?; - } else if account_info.data_len() == size_of::() { + } else if account_info.data_len() == Mint::get_packed_len() { let mut mint_data = account_info.data.borrow_mut(); Mint::unpack_mut(&mut mint_data, &mut |mint: &mut Mint| { match authority_type { @@ -716,7 +715,7 @@ impl Processor { return Err(TokenError::OwnerMismatch.into()); } if program_id == owner_account_info.owner - && owner_account_info.data_len() == std::mem::size_of::() + && owner_account_info.data_len() == Multisig::get_packed_len() { let mut owner_data = owner_account_info.data.borrow_mut(); Multisig::unpack_mut(&mut owner_data, &mut |multisig: &mut Multisig| { @@ -825,15 +824,15 @@ mod tests { } fn mint_minimum_balance() -> u64 { - Rent::default().minimum_balance(size_of::()) + Rent::default().minimum_balance(Mint::get_packed_len()) } fn account_minimum_balance() -> u64 { - Rent::default().minimum_balance(size_of::()) + Rent::default().minimum_balance(Account::get_packed_len()) } fn multisig_minimum_balance() -> u64 { - Rent::default().minimum_balance(size_of::()) + Rent::default().minimum_balance(Multisig::get_packed_len()) } #[test] @@ -850,12 +849,117 @@ mod tests { #[test] fn test_unique_account_sizes() { - assert_ne!(size_of::(), 0); - assert_ne!(size_of::(), size_of::()); - assert_ne!(size_of::(), size_of::()); - assert_ne!(size_of::(), 0); - assert_ne!(size_of::(), size_of::()); - assert_ne!(size_of::(), 0); + assert_ne!(Mint::get_packed_len(), 0); + assert_ne!(Mint::get_packed_len(), Account::get_packed_len()); + assert_ne!(Mint::get_packed_len(), Multisig::get_packed_len()); + assert_ne!(Account::get_packed_len(), 0); + assert_ne!(Account::get_packed_len(), Multisig::get_packed_len()); + assert_ne!(Multisig::get_packed_len(), 0); + } + + #[test] + fn test_pack_unpack() { + // Mint + let check = Mint { + mint_authority: COption::Some(Pubkey::new(&[1; 32])), + supply: 42, + decimals: 7, + is_initialized: true, + freeze_authority: COption::Some(Pubkey::new(&[2; 32])), + }; + let mut packed = vec![0; Mint::get_packed_len() + 1]; + assert_eq!( + Err(ProgramError::InvalidAccountData), + Mint::pack(check, &mut packed) + ); + let mut packed = vec![0; Mint::get_packed_len() - 1]; + assert_eq!( + Err(ProgramError::InvalidAccountData), + Mint::pack(check, &mut packed) + ); + let mut packed = vec![0; Mint::get_packed_len()]; + Mint::pack(check, &mut packed).unwrap(); + let expect = vec![ + 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 42, 0, 0, 0, 0, 0, 0, 0, 7, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + ]; + assert_eq!(packed, expect); + let unpacked = Mint::unpack(&packed).unwrap(); + assert_eq!(unpacked, check); + + // Account + let check = Account { + mint: Pubkey::new(&[1; 32]), + owner: Pubkey::new(&[2; 32]), + amount: 3, + delegate: COption::Some(Pubkey::new(&[4; 32])), + state: AccountState::Frozen, + is_native: COption::Some(5), + delegated_amount: 6, + close_authority: COption::Some(Pubkey::new(&[7; 32])), + }; + let mut packed = vec![0; Account::get_packed_len() + 1]; + assert_eq!( + Err(ProgramError::InvalidAccountData), + Account::pack(check, &mut packed) + ); + let mut packed = vec![0; Account::get_packed_len() - 1]; + assert_eq!( + Err(ProgramError::InvalidAccountData), + Account::pack(check, &mut packed) + ); + let mut packed = vec![0; Account::get_packed_len()]; + Account::pack(check, &mut packed).unwrap(); + let expect = vec![ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, 0, 0, 0, 5, 0, 0, + 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + ]; + assert_eq!(packed, expect); + let unpacked = Account::unpack(&packed).unwrap(); + assert_eq!(unpacked, check); + + // Multisig + let check = Multisig { + m: 1, + n: 2, + is_initialized: true, + signers: [Pubkey::new(&[3; 32]); MAX_SIGNERS], + }; + let mut packed = vec![0; Multisig::get_packed_len() + 1]; + assert_eq!( + Err(ProgramError::InvalidAccountData), + Multisig::pack(check, &mut packed) + ); + let mut packed = vec![0; Multisig::get_packed_len() - 1]; + assert_eq!( + Err(ProgramError::InvalidAccountData), + Multisig::pack(check, &mut packed) + ); + let mut packed = vec![0; Multisig::get_packed_len()]; + Multisig::pack(check, &mut packed).unwrap(); + let expect = vec![ + 1, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, + ]; + assert_eq!(packed, expect); + let unpacked = Multisig::unpack(&packed).unwrap(); + assert_eq!(unpacked, check); } #[test] @@ -863,10 +967,10 @@ mod tests { let program_id = pubkey_rand(); let owner_key = pubkey_rand(); let mint_key = pubkey_rand(); - let mut mint_account = SolanaAccount::new(42, size_of::(), &program_id); + let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); let mint2_key = pubkey_rand(); let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); // mint is not rent exempt @@ -913,12 +1017,12 @@ mod tests { fn test_initialize_mint_account() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = SolanaAccount::new(42, size_of::(), &program_id); + let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); // account is not rent exempt @@ -989,26 +1093,38 @@ mod tests { fn test_transfer() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account3_key = pubkey_rand(); - let mut account3_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); let mismatch_key = pubkey_rand(); - let mut mismatch_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint2_key = pubkey_rand(); let mut rent_sysvar = rent_sysvar(); @@ -1438,13 +1554,16 @@ mod tests { fn test_mintable_token_with_zero_supply() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); // create mint-able token with zero supply @@ -1546,11 +1665,17 @@ mod tests { fn test_approve() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); let owner_key = pubkey_rand(); @@ -1559,7 +1684,7 @@ mod tests { let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); // create mint @@ -1745,11 +1870,17 @@ mod tests { fn test_set_authority() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); @@ -1757,10 +1888,10 @@ mod tests { let owner3_key = pubkey_rand(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint2_key = pubkey_rand(); let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); // create new mint with owner @@ -2078,28 +2209,43 @@ mod tests { fn test_mint_to() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account3_key = pubkey_rand(); - let mut account3_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let mismatch_key = pubkey_rand(); - let mut mismatch_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint2_key = pubkey_rand(); let uninitialized_key = pubkey_rand(); - let mut uninitialized_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut uninitialized_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let mut rent_sysvar = rent_sysvar(); // create new mint with owner @@ -2280,26 +2426,38 @@ mod tests { fn test_burn() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account3_key = pubkey_rand(); - let mut account3_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); let mismatch_key = pubkey_rand(); - let mut mismatch_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint2_key = pubkey_rand(); let mut rent_sysvar = rent_sysvar(); @@ -2542,21 +2700,27 @@ mod tests { let program_id = pubkey_rand(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let account_key = pubkey_rand(); - let mut account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let multisig_key = pubkey_rand(); - let mut multisig_account = SolanaAccount::new(42, size_of::(), &program_id); + let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id); let multisig_delegate_key = pubkey_rand(); let mut multisig_delegate_account = SolanaAccount::new( multisig_minimum_balance(), - size_of::(), + Multisig::get_packed_len(), &program_id, ); let signer_keys = vec![pubkey_rand(); MAX_SIGNERS]; @@ -2826,11 +2990,14 @@ mod tests { // freeze account let account3_key = pubkey_rand(); - let mut account3_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let mint2_key = pubkey_rand(); let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); do_process_instruction( initialize_mint( &program_id, @@ -2959,7 +3126,7 @@ mod tests { signer.key = key; } let mut lamports = 0; - let mut data = vec![0; size_of::()]; + let mut data = vec![0; Multisig::get_packed_len()]; Multisig::unpack_unchecked_mut(&mut data, &mut |multisig: &mut Multisig| { multisig.m = MAX_SIGNERS as u8; multisig.n = MAX_SIGNERS as u8; @@ -3085,19 +3252,25 @@ mod tests { let program_id = pubkey_rand(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); let mut account2_account = SolanaAccount::new( account_minimum_balance() + 42, - size_of::(), + Account::get_packed_len(), &program_id, ); let account3_key = pubkey_rand(); - let mut account3_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); @@ -3227,11 +3400,17 @@ mod tests { // fund and initialize new non-native account to test close authority let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner2_key = pubkey_rand(); - let mut owner2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut owner2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), vec![ @@ -3316,16 +3495,19 @@ mod tests { fn test_native_token() { let program_id = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let account_key = pubkey_rand(); let mut account_account = SolanaAccount::new( account_minimum_balance() + 40, - size_of::(), + Account::get_packed_len(), &program_id, ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account3_key = pubkey_rand(); let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); let owner_key = pubkey_rand(); @@ -3400,7 +3582,7 @@ mod tests { // burn unsupported let bogus_mint_key = pubkey_rand(); let mut bogus_mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); do_process_instruction( initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(), vec![&mut bogus_mint_account, &mut rent_sysvar], @@ -3505,11 +3687,17 @@ mod tests { fn test_overflow() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let owner2_key = pubkey_rand(); @@ -3518,7 +3706,7 @@ mod tests { let mut mint_owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); // create new mint with owner @@ -3690,16 +3878,22 @@ mod tests { fn test_frozen() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account2_key = pubkey_rand(); - let mut account2_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = pubkey_rand(); let mut owner_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); // create new mint and fund first account @@ -3880,8 +4074,11 @@ mod tests { fn test_freeze_account() { let program_id = pubkey_rand(); let account_key = pubkey_rand(); - let mut account_account = - SolanaAccount::new(account_minimum_balance(), size_of::(), &program_id); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let account_owner_key = pubkey_rand(); let mut account_owner_account = SolanaAccount::default(); let owner_key = pubkey_rand(); @@ -3890,7 +4087,7 @@ mod tests { let mut owner2_account = SolanaAccount::default(); let mint_key = pubkey_rand(); let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), size_of::(), &program_id); + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); // create new mint with owner different from account owner diff --git a/program/src/state.rs b/program/src/state.rs index 08de37e..5d14af7 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -10,9 +10,6 @@ use num_enum::TryFromPrimitive; use solana_sdk::{program_error::ProgramError, pubkey::Pubkey}; impl Sealed for Option {} -impl Sealed for Mint {} -impl Sealed for Account {} -impl Sealed for Multisig {} /// Mint data. #[repr(C)] @@ -31,6 +28,7 @@ pub struct Mint { /// Optional authority to freeze token accounts. pub freeze_authority: COption, } +impl Sealed for Mint {} impl IsInitialized for Mint { fn is_initialized(&self) -> bool { self.is_initialized @@ -117,6 +115,7 @@ impl Account { self.is_native.is_some() } } +impl Sealed for Account {} impl IsInitialized for Account { fn is_initialized(&self) -> bool { self.state != AccountState::Uninitialized @@ -206,6 +205,7 @@ pub struct Multisig { /// Signer public keys pub signers: [Pubkey; MAX_SIGNERS], } +impl Sealed for Multisig {} impl IsInitialized for Multisig { fn is_initialized(&self) -> bool { self.is_initialized From b28d1d706ce670180fdea62b7b295b37bc31776c Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Sat, 29 Aug 2020 02:44:03 -0600 Subject: [PATCH 056/335] Bump token program id, version (#361) --- program/Cargo.toml | 2 +- program/program-id.md | 2 +- program/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 45f7856..7f74922 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "2.0.1" +version = "2.0.3" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" diff --git a/program/program-id.md b/program/program-id.md index 6f7f354..f397edf 100644 --- a/program/program-id.md +++ b/program/program-id.md @@ -1 +1 @@ -TokenFSDHBLHfbT65SnYJx77ysXc1WTC2W3kvnXnZZR +TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA diff --git a/program/src/lib.rs b/program/src/lib.rs index 2addcd2..52dc77f 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -27,4 +27,4 @@ pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { amount as f64 / 10_usize.pow(decimals as u32) as f64 } -solana_sdk::declare_id!("TokenFSDHBLHfbT65SnYJx77ysXc1WTC2W3kvnXnZZR"); +solana_sdk::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); From 1e549d7c21ac156e34b89cba0c12888c6e4af2e3 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Sat, 29 Aug 2020 14:42:18 -0700 Subject: [PATCH 057/335] Update to Solana 1.3.6 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 7f74922..4a72b1b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,7 +21,7 @@ default = ["solana-sdk/default"] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.4", default-features = false, optional = true } +solana-sdk = { version = "1.3.6", default-features = false, optional = true } thiserror = "1.0" arrayref = "0.3.6" num_enum = "0.5.1" From f9c87315a6982f31c10d76871442284fcd6802ad Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Sat, 29 Aug 2020 21:59:35 -0700 Subject: [PATCH 058/335] Fix up doc quotes --- program/src/instruction.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index d51c8dd..bd19a9e 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -173,9 +173,9 @@ pub enum TokenInstruction { /// /// * Multisignature owner/delegate /// 0. `[writable]` The account to burn from. - /// 1. '[writable]' The token mint. + /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M '[signer]' M signer accounts. + /// 3. ..3+M `[signer]` M signer accounts. Burn { /// The amount of tokens to burn. amount: u64, From 23c437d87ad34bf7b8713a0c018b1083a352c69d Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Thu, 3 Sep 2020 20:17:12 -0600 Subject: [PATCH 059/335] Bump solana crates to 1.3.8 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 4a72b1b..4c1c6f3 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,7 +21,7 @@ default = ["solana-sdk/default"] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.6", default-features = false, optional = true } +solana-sdk = { version = "1.3.8", default-features = false, optional = true } thiserror = "1.0" arrayref = "0.3.6" num_enum = "0.5.1" From da3a7b9d6c2be9c2b31192d76fb3031b30f63d1d Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Thu, 3 Sep 2020 20:21:52 -0600 Subject: [PATCH 060/335] Bump Token version to 2.0.4 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 4c1c6f3..63176a6 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "2.0.3" +version = "2.0.4" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 71f921aa3a6efa3205d6f6500ce901e7693ca79d Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Thu, 3 Sep 2020 21:09:13 -0600 Subject: [PATCH 061/335] Unrelated clippy... --- program/src/native_mint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs index 622199c..740b8ab 100644 --- a/program/src/native_mint.rs +++ b/program/src/native_mint.rs @@ -14,7 +14,7 @@ mod tests { #[test] fn test_decimals() { assert!( - lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS).abs() < f64::EPSILON + (lamports_to_sol(42) - crate::amount_to_ui_amount(42, DECIMALS)).abs() < f64::EPSILON ); assert_eq!( sol_to_lamports(42.), From d8cda089dd9aa4773bb08e8db6d9e01ffd0a6b9c Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Thu, 10 Sep 2020 17:25:43 +0800 Subject: [PATCH 062/335] Bump dependencies from 1.3.8 to 1.3.9 (#415) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 63176a6..9debf93 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,7 +21,7 @@ default = ["solana-sdk/default"] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.8", default-features = false, optional = true } +solana-sdk = { version = "1.3.9", default-features = false, optional = true } thiserror = "1.0" arrayref = "0.3.6" num_enum = "0.5.1" From c99311c21033090ffd92fb9f44663b2417eb5f79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2020 09:22:53 +0000 Subject: [PATCH 063/335] Bump solana-sdk from 1.3.9 to 1.3.11 (#454) Bumps [solana-sdk](https://github.com/solana-labs/solana) from 1.3.9 to 1.3.11. - [Release notes](https://github.com/solana-labs/solana/releases) - [Changelog](https://github.com/solana-labs/solana/blob/master/RELEASE.md) - [Commits](https://github.com/solana-labs/solana/compare/v1.3.9...v1.3.11) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 9debf93..fbba104 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,7 +21,7 @@ default = ["solana-sdk/default"] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.9", default-features = false, optional = true } +solana-sdk = { version = "1.3.11", default-features = false, optional = true } thiserror = "1.0" arrayref = "0.3.6" num_enum = "0.5.1" From c29bca3dabc687a03eb8ff9746ab5ca4d6fcd737 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 16 Sep 2020 08:55:03 -0700 Subject: [PATCH 064/335] Nit: add current --- program/src/instruction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index bd19a9e..5c8e1b0 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -135,7 +135,7 @@ pub enum TokenInstruction { /// /// * Multisignature authority /// 0. `[writable]` The mint or account to change the authority of. - /// 1. `[]` The mint's or account's multisignature authority. + /// 1. `[]` The mint's or account's current multisignature authority. /// 2. ..2+M `[signer]` M signer accounts SetAuthority { /// The type of authority to update. From 1f1239f3a8f4c3ad8e85cef4cd10e1c0162403db Mon Sep 17 00:00:00 2001 From: Jack May Date: Fri, 18 Sep 2020 15:53:26 -0700 Subject: [PATCH 065/335] Fix multisign check (#479) --- program/src/instruction.rs | 19 +++++++++++-------- program/src/processor.rs | 17 +++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 5c8e1b0..2e2d990 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -56,11 +56,14 @@ pub enum TokenInstruction { InitializeAccount, /// Initializes a multisignature account with N provided signers. /// + /// Warning, this instruction is compromised: + /// https://github.com/solana-labs/solana-program-library/issues/477 + /// /// Multisignature accounts can used in place of any single owner/delegate accounts in any /// token instruction that require an owner/delegate to be present. The variant field represents the /// number of signers (M) required to validate this multisignature account. /// - /// The `InitializeMultisig` instruction requires no signers and MUST be included within + /// The `DangerInitializeMultisig` instruction requires no signers and MUST be included within /// the same Transaction as the system program's `CreateInstruction` that creates the account /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. /// @@ -69,7 +72,7 @@ pub enum TokenInstruction { /// 0. `[writable]` The multisignature account to initialize. /// 1. `[]` Rent sysvar /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. - InitializeMultisig { + DangerInitializeMultisig { /// The number of signers (M) required to validate this multisignature account. m: u8, }, @@ -350,7 +353,7 @@ impl TokenInstruction { 1 => Self::InitializeAccount, 2 => { let &m = rest.get(0).ok_or(InvalidInstruction)?; - Self::InitializeMultisig { m } + Self::DangerInitializeMultisig { m } } 3 | 4 | 7 | 8 => { let amount = rest @@ -446,7 +449,7 @@ impl TokenInstruction { Self::pack_pubkey_option(freeze_authority, &mut buf); } Self::InitializeAccount => buf.push(1), - &Self::InitializeMultisig { m } => { + &Self::DangerInitializeMultisig { m } => { buf.push(2); buf.push(m); } @@ -621,8 +624,8 @@ pub fn initialize_account( }) } -/// Creates a `InitializeMultisig` instruction. -pub fn initialize_multisig( +/// Creates a `DangerInitializeMultisig` instruction. +pub fn danger_initialize_multisig( token_program_id: &Pubkey, multisig_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], @@ -634,7 +637,7 @@ pub fn initialize_multisig( { return Err(ProgramError::MissingRequiredSignature); } - let data = TokenInstruction::InitializeMultisig { m }.pack(); + let data = TokenInstruction::DangerInitializeMultisig { m }.pack(); let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*multisig_pubkey, false)); @@ -1080,7 +1083,7 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); - let check = TokenInstruction::InitializeMultisig { m: 1 }; + let check = TokenInstruction::DangerInitializeMultisig { m: 1 }; let packed = check.pack(); let expect = Vec::from([2u8, 1]); assert_eq!(packed, expect); diff --git a/program/src/processor.rs b/program/src/processor.rs index 32d3f7e..3901cf4 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -99,8 +99,8 @@ impl Processor { }) } - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. - pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { + /// Processes a [DangerInitializeMultisig](enum.TokenInstruction.html) instruction. + pub fn process_danger_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let multisig_info = next_account_info(account_info_iter)?; let multisig_info_data_len = multisig_info.data_len(); @@ -642,9 +642,9 @@ impl Processor { info!("Instruction: InitializeAccount"); Self::process_initialize_account(accounts) } - TokenInstruction::InitializeMultisig { m } => { - info!("Instruction: InitializeMultisig"); - Self::process_initialize_multisig(accounts, m) + TokenInstruction::DangerInitializeMultisig { m } => { + info!("Instruction: DangerInitializeMultisig"); + Self::process_danger_initialize_multisig(accounts, m) } TokenInstruction::Transfer { amount } => { info!("Instruction: Transfer"); @@ -2733,7 +2733,8 @@ mod tests { assert_eq!( Err(TokenError::NotRentExempt.into()), do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + danger_initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1) + .unwrap(), vec![ &mut multisig_account, &mut rent_sysvar, @@ -2747,7 +2748,7 @@ mod tests { // single signer let account_info_iter = &mut signer_accounts.iter_mut(); do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + danger_initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), vec![ &mut multisig_account, &mut rent_sysvar, @@ -2759,7 +2760,7 @@ mod tests { // multiple signer let account_info_iter = &mut signer_accounts.iter_mut(); do_process_instruction( - initialize_multisig( + danger_initialize_multisig( &program_id, &multisig_delegate_key, &signer_key_refs, From f27e85ed0c6f1da476440e37a5d15b6c125b7ad1 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 18 Sep 2020 18:37:21 -0600 Subject: [PATCH 066/335] Bump spl-token v2 (#480) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index fbba104..16e174f 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "2.0.4" +version = "2.0.5" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From d589bba3543a9c923b65afc472181870d13243b2 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 12:43:32 -0700 Subject: [PATCH 067/335] backport #433 to v2 --- program/src/processor.rs | 337 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 328 insertions(+), 9 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 3901cf4..38d3cbc 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -161,19 +161,18 @@ impl Processor { return Ok(()); } - let mut source_data = source_account_info.data.borrow_mut(); - let mut dest_data = dest_account_info.data.borrow_mut(); - Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { - Account::unpack_mut(&mut dest_data, &mut |dest_account: &mut Account| { + let mut source_account = Account::unpack(&source_account_info.data.borrow())?; + let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; + if source_account.amount < amount { return Err(TokenError::InsufficientFunds.into()); } - if source_account.mint != dest_account.mint { - return Err(TokenError::MintMismatch.into()); - } if source_account.is_frozen() || dest_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } + if source_account.mint != dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } if let Some((mint_info, expected_decimals)) = expected_mint_info { if source_account.mint != *mint_info.key { @@ -234,9 +233,10 @@ impl Processor { .ok_or(TokenError::Overflow)?; } + Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?; + Ok(()) - }) - }) } /// Processes an [Approve](enum.TokenInstruction.html) instruction. @@ -815,6 +815,13 @@ mod tests { Processor::process(&instruction.program_id, &account_infos, &instruction.data) } + fn do_process_instruction_dups( + instruction: Instruction, + account_infos: Vec, + ) -> ProgramResult { + Processor::process(&instruction.program_id, &account_infos, &instruction.data) + } + fn return_token_error_as_program_error() -> ProgramError { TokenError::MintMismatch.into() } @@ -1089,6 +1096,318 @@ mod tests { ); } + #[test] + fn test_transfer_dups() { + let program_id = pubkey_rand(); + let account1_key = pubkey_rand(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into(); + let account4_key = pubkey_rand(); + let mut account4_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into(); + let multisig_key = pubkey_rand(); + let mut multisig_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = pubkey_rand(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // create another account + do_process_instruction_dups( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + account2_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint to account + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-owner transfer + do_process_instruction_dups( + transfer( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner transfer2 + do_process_instruction_dups( + transfer2( + &program_id, + &account1_key, + &mint_key, + &account2_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-delegate transfer + Account::unpack_unchecked_mut( + &mut account1_info.data.borrow_mut(), + &mut |account: &mut Account| { + account.amount = 1000; + account.delegated_amount = 1000; + account.delegate = COption::Some(account1_key); + account.owner = owner_key; + Ok(()) + }, + ) + .unwrap(); + + do_process_instruction_dups( + transfer( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-delegate transfer2 + do_process_instruction_dups( + transfer2( + &program_id, + &account1_key, + &mint_key, + &account2_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // test destination-owner transfer + do_process_instruction_dups( + initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + account2_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], + ) + .unwrap(); + + account1_info.is_signer = false; + account2_info.is_signer = true; + do_process_instruction_dups( + transfer( + &program_id, + &account3_key, + &account2_key, + &account2_key, + &[], + 500, + ) + .unwrap(), + vec![ + account3_info.clone(), + account2_info.clone(), + account2_info.clone(), + ], + ) + .unwrap(); + + // destination-owner transfer2 + do_process_instruction_dups( + transfer2( + &program_id, + &account3_key, + &mint_key, + &account2_key, + &account2_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + account2_info.clone(), + account2_info.clone(), + ], + ) + .unwrap(); + + // test source-multisig signer + do_process_instruction_dups( + initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(), + vec![ + multisig_info.clone(), + rent_info.clone(), + account4_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(), + vec![ + account4_info.clone(), + mint_info.clone(), + multisig_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account4_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-multisig-signer transfer + do_process_instruction_dups( + transfer( + &program_id, + &account4_key, + &account2_key, + &multisig_key, + &[&account4_key], + 500, + ) + .unwrap(), + vec![ + account4_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account4_info.clone(), + ], + ) + .unwrap(); + + // source-multisig-signer transfer2 + do_process_instruction_dups( + transfer2( + &program_id, + &account4_key, + &mint_key, + &account2_key, + &multisig_key, + &[&account4_key], + 500, + 2, + ) + .unwrap(), + vec![ + account4_info.clone(), + mint_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account4_info.clone(), + ], + ) + .unwrap(); + } + #[test] fn test_transfer() { let program_id = pubkey_rand(); From 7d793af951b6e16844343ac406fe23350cc2af15 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 12:45:24 -0700 Subject: [PATCH 068/335] backport #438 to v2 --- program/src/processor.rs | 172 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 6 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 38d3cbc..4618abe 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -552,8 +552,7 @@ impl Processor { let dest_account_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; - let mut source_data = source_account_info.data.borrow_mut(); - Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + let mut source_account = Account::unpack(&source_account_info.data.borrow())?; if !source_account.is_native() && source_account.amount != 0 { return Err(TokenError::NonNativeHasBalance.into()); } @@ -576,8 +575,9 @@ impl Processor { **source_account_info.lamports.borrow_mut() = 0; source_account.amount = 0; + Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + Ok(()) - }) } /// Processes a [FreezeAccount](enum.TokenInstruction.html) or a @@ -592,8 +592,7 @@ impl Processor { let mint_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; - let mut source_data = source_account_info.data.borrow_mut(); - Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + let mut source_account = Account::unpack(&source_account_info.data.borrow())?; if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } @@ -621,8 +620,9 @@ impl Processor { AccountState::Initialized }; + Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + Ok(()) - }) } /// Processes an [Instruction](enum.Instruction.html). @@ -3567,6 +3567,97 @@ mod tests { signers[5].is_signer = true; } + #[test] + fn test_close_account_dups() { + let program_id = pubkey_rand(); + let account1_key = pubkey_rand(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_info: AccountInfo = (&account2_key, true, &mut account2_account).into(); + let owner_key = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // source-owner close + do_process_instruction_dups( + close_account( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-close-authority close + Account::unpack_unchecked_mut( + &mut account1_info.data.borrow_mut(), + &mut |account: &mut Account| { + account.close_authority = COption::Some(account1_key); + account.owner = owner_key; + Ok(()) + }, + ) + .unwrap(); + do_process_instruction_dups( + close_account( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + } + #[test] fn test_close_account() { let program_id = pubkey_rand(); @@ -4390,6 +4481,75 @@ mod tests { ); } + #[test] + fn test_freeze_thaw_dups() { + let program_id = pubkey_rand(); + let account1_key = pubkey_rand(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // freeze where mint freeze_authority is account + do_process_instruction_dups( + freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // thaw where mint freeze_authority is account + Account::unpack_unchecked_mut( + &mut account1_info.data.borrow_mut(), + &mut |account: &mut Account| { + account.state = AccountState::Frozen; + Ok(()) + }, + ) + .unwrap(); + do_process_instruction_dups( + thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + } + #[test] fn test_freeze_account() { let program_id = pubkey_rand(); From 041c33a18dc86f139614d850bac8d37238f98692 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 12:46:42 -0700 Subject: [PATCH 069/335] backport #437 to v2 --- program/src/processor.rs | 227 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 221 insertions(+), 6 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 4618abe..4d7c070 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -480,10 +480,9 @@ impl Processor { let mint_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; - let mut mint_data = mint_info.data.borrow_mut(); - let mut source_data = source_account_info.data.borrow_mut(); - Mint::unpack_mut(&mut mint_data, &mut |mint: &mut Mint| { - Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + let mut source_account = Account::unpack(&source_account_info.data.borrow())?; + let mut mint = Mint::unpack(&mint_info.data.borrow())?; + if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } @@ -540,9 +539,10 @@ impl Processor { .checked_sub(amount) .ok_or(TokenError::Overflow)?; + Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + Mint::pack(mint, &mut mint_info.data.borrow_mut())?; + Ok(()) - }) - }) } /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. @@ -2741,6 +2741,221 @@ mod tests { ); } + #[test] + fn test_burn_dups() { + let program_id = pubkey_rand(); + let account1_key = pubkey_rand(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = pubkey_rand(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint to account + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-owner burn + do_process_instruction_dups( + burn( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner burn2 + do_process_instruction_dups( + burn2( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint-owner burn + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + Account::unpack_unchecked_mut( + &mut account1_info.data.borrow_mut(), + &mut |account: &mut Account| { + account.owner = mint_key; + Ok(()) + }, + ) + .unwrap(); + do_process_instruction_dups( + burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint-owner burn2 + do_process_instruction_dups( + burn2( + &program_id, + &account1_key, + &mint_key, + &mint_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // source-delegate burn + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + Account::unpack_unchecked_mut( + &mut account1_info.data.borrow_mut(), + &mut |account: &mut Account| { + account.delegated_amount = 1000; + account.delegate = COption::Some(account1_key); + account.owner = owner_key; + Ok(()) + }, + ) + .unwrap(); + do_process_instruction_dups( + burn( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-delegate burn2 + do_process_instruction_dups( + burn2( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint-delegate burn + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + Account::unpack_unchecked_mut( + &mut account1_info.data.borrow_mut(), + &mut |account: &mut Account| { + account.delegated_amount = 1000; + account.delegate = COption::Some(mint_key); + account.owner = owner_key; + Ok(()) + }, + ) + .unwrap(); + do_process_instruction_dups( + burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint-delegate burn2 + do_process_instruction_dups( + burn2( + &program_id, + &account1_key, + &mint_key, + &mint_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + } + #[test] fn test_burn() { let program_id = pubkey_rand(); From 7b54f8639cffa633dadb81f9004482c7de12261a Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 12:47:55 -0700 Subject: [PATCH 070/335] backport #436 to v2 --- program/src/processor.rs | 109 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 4d7c070..466b644 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -421,8 +421,7 @@ impl Processor { let dest_account_info = next_account_info(account_info_iter)?; let owner_info = next_account_info(account_info_iter)?; - let mut dest_account_data = dest_account_info.data.borrow_mut(); - Account::unpack_mut(&mut dest_account_data, &mut |dest_account: &mut Account| { + let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; if dest_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } @@ -434,8 +433,7 @@ impl Processor { return Err(TokenError::MintMismatch.into()); } - let mut mint_data = mint_info.data.borrow_mut(); - Mint::unpack_mut(&mut mint_data, &mut |mint: &mut Mint| { + let mut mint = Mint::unpack(&mint_info.data.borrow())?; if let Some(expected_decimals) = expected_decimals { if expected_decimals != mint.decimals { return Err(TokenError::MintDecimalsMismatch.into()); @@ -462,9 +460,10 @@ impl Processor { .checked_add(amount) .ok_or(TokenError::Overflow)?; + Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?; + Mint::pack(mint, &mut mint_info.data.borrow_mut())?; + Ok(()) - }) - }) } /// Processes a [Burn](enum.TokenInstruction.html) instruction. @@ -2524,6 +2523,104 @@ mod tests { ); } + #[test] + fn test_mint_to_dups() { + let program_id = pubkey_rand(); + let account1_key = pubkey_rand(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = pubkey_rand(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &owner_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint_to when mint_authority is self + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(), + vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint_to2 when mint_authority is self + do_process_instruction_dups( + mint_to2(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), + vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint_to when mint_authority is account owner + Mint::unpack_unchecked_mut(&mut mint_info.data.borrow_mut(), &mut |mint: &mut Mint| { + mint.mint_authority = COption::Some(account1_key); + Ok(()) + }) + .unwrap(); + do_process_instruction_dups( + mint_to( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 42, + ) + .unwrap(), + vec![ + mint_info.clone(), + account1_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint_to2 when mint_authority is account owner + do_process_instruction_dups( + mint_to( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 42, + ) + .unwrap(), + vec![ + mint_info.clone(), + account1_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + } + #[test] fn test_mint_to() { let program_id = pubkey_rand(); From dd5dcdac1216791797d7b925c6468e38de05e8dc Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 12:48:58 -0700 Subject: [PATCH 071/335] backport #435 to v2 --- program/src/processor.rs | 121 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 8 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 466b644..5ef4395 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -327,8 +327,8 @@ impl Processor { let authority_info = next_account_info(account_info_iter)?; if account_info.data_len() == Account::get_packed_len() { - let mut account_data = account_info.data.borrow_mut(); - Account::unpack_mut(&mut account_data, &mut |account: &mut Account| { + let mut account = Account::unpack(&account_info.data.borrow())?; + if account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } @@ -362,11 +362,9 @@ impl Processor { return Err(TokenError::AuthorityTypeNotSupported.into()); } } - Ok(()) - })?; + Account::pack(account, &mut account_info.data.borrow_mut())?; } else if account_info.data_len() == Mint::get_packed_len() { - let mut mint_data = account_info.data.borrow_mut(); - Mint::unpack_mut(&mut mint_data, &mut |mint: &mut Mint| { + let mut mint = Mint::unpack(&account_info.data.borrow())?; match authority_type { AuthorityType::MintTokens => { // Once a mint's supply is fixed, it cannot be undone by setting a new @@ -400,8 +398,7 @@ impl Processor { return Err(TokenError::AuthorityTypeNotSupported.into()); } } - Ok(()) - })?; + Mint::pack(mint, &mut account_info.data.borrow_mut())?; } else { return Err(ProgramError::InvalidArgument); } @@ -2184,6 +2181,114 @@ mod tests { .unwrap(); } + #[test] + fn test_set_authority_dups() { + let program_id = pubkey_rand(); + let account1_key = pubkey_rand(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = pubkey_rand(); + let mint_key = pubkey_rand(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // set mint_authority when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::MintTokens, + &mint_key, + &[], + ) + .unwrap(), + vec![mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // set freeze_authority when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::FreezeAccount, + &mint_key, + &[], + ) + .unwrap(), + vec![mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // set account owner when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &account1_key, + Some(&owner_key), + AuthorityType::AccountOwner, + &account1_key, + &[], + ) + .unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); + + // set close_authority when currently self + Account::unpack_unchecked_mut( + &mut account1_info.data.borrow_mut(), + &mut |account: &mut Account| { + account.close_authority = COption::Some(account1_key); + Ok(()) + }, + ) + .unwrap(); + + do_process_instruction_dups( + set_authority( + &program_id, + &account1_key, + Some(&owner_key), + AuthorityType::CloseAccount, + &account1_key, + &[], + ) + .unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); + } + #[test] fn test_set_authority() { let program_id = pubkey_rand(); From 61670b05f4c9dea6e41081bb9556351f172847eb Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 12:49:57 -0700 Subject: [PATCH 072/335] backport #434 to v2 --- program/src/processor.rs | 225 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 219 insertions(+), 6 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 5ef4395..1508a02 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -257,8 +257,8 @@ impl Processor { let delegate_info = next_account_info(account_info_iter)?; let owner_info = next_account_info(account_info_iter)?; - let mut source_data = source_account_info.data.borrow_mut(); - Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + let mut source_account = Account::unpack(&source_account_info.data.borrow())?; + if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } @@ -284,8 +284,9 @@ impl Processor { source_account.delegate = COption::Some(*delegate_info.key); source_account.delegated_amount = amount; + Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + Ok(()) - }) } /// Processes an [Revoke](enum.TokenInstruction.html) instruction. @@ -293,8 +294,8 @@ impl Processor { let account_info_iter = &mut accounts.iter(); let source_account_info = next_account_info(account_info_iter)?; - let mut source_data = source_account_info.data.borrow_mut(); - Account::unpack_mut(&mut source_data, &mut |source_account: &mut Account| { + let mut source_account = Account::unpack(&source_account_info.data.borrow())?; + let owner_info = next_account_info(account_info_iter)?; if source_account.is_frozen() { @@ -311,8 +312,9 @@ impl Processor { source_account.delegate = COption::None; source_account.delegated_amount = 0; + Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + Ok(()) - }) } /// Processes a [SetAuthority](enum.TokenInstruction.html) instruction. @@ -1976,6 +1978,217 @@ mod tests { .unwrap(); } + #[test] + fn test_approve_dups() { + let program_id = pubkey_rand(); + let account1_key = pubkey_rand(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let account2_key = pubkey_rand(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); + let account3_key = pubkey_rand(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into(); + let multisig_key = pubkey_rand(); + let mut multisig_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); + let owner_key = pubkey_rand(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = pubkey_rand(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // create another account + do_process_instruction_dups( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + account2_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint to account + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-owner approve + do_process_instruction_dups( + approve( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner approve2 + do_process_instruction_dups( + approve2( + &program_id, + &account1_key, + &mint_key, + &account2_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner revoke + do_process_instruction_dups( + revoke(&program_id, &account1_key, &account1_key, &[]).unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); + + // test source-multisig signer + do_process_instruction_dups( + initialize_multisig(&program_id, &multisig_key, &[&account3_key], 1).unwrap(), + vec![ + multisig_info.clone(), + rent_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + initialize_account(&program_id, &account3_key, &mint_key, &multisig_key).unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + multisig_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-multisig-signer approve + do_process_instruction_dups( + approve( + &program_id, + &account3_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + ) + .unwrap(), + vec![ + account3_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + // source-multisig-signer approve2 + do_process_instruction_dups( + approve2( + &program_id, + &account3_key, + &mint_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + 2, + ) + .unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + // source-owner multisig-signer + do_process_instruction_dups( + revoke(&program_id, &account3_key, &multisig_key, &[&account3_key]).unwrap(), + vec![ + account3_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + } + #[test] fn test_approve() { let program_id = pubkey_rand(); From 39d49dd357973090efadf38b9bb4d9ef9c9bd6f0 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 12:55:45 -0700 Subject: [PATCH 073/335] backport #443 to v2 --- program/src/pack.rs | 27 --- program/src/processor.rs | 371 +++++++++++---------------------------- 2 files changed, 101 insertions(+), 297 deletions(-) diff --git a/program/src/pack.rs b/program/src/pack.rs index 7a86cb9..106b51b 100644 --- a/program/src/pack.rs +++ b/program/src/pack.rs @@ -47,33 +47,6 @@ pub trait Pack: Sealed { Ok(Self::unpack_from_slice(input)?) } - /// Borrow `Self` from `input` for the duration of the call to `f`, but first check that `Self` - /// is initialized - #[inline(never)] - fn unpack_mut(input: &mut [u8], f: &mut F) -> Result - where - F: FnMut(&mut Self) -> Result, - Self: IsInitialized, - { - let mut t = Self::unpack(input)?; - let u = f(&mut t)?; - Self::pack(t, input)?; - Ok(u) - } - - /// Borrow `Self` from `input` for the duration of the call to `f`, without checking that - /// `Self` has been initialized - #[inline(never)] - fn unpack_unchecked_mut(input: &mut [u8], f: &mut F) -> Result - where - F: FnMut(&mut Self) -> Result, - { - let mut t = Self::unpack_unchecked(input)?; - let u = f(&mut t)?; - Self::pack(t, input)?; - Ok(u) - } - /// Pack into slice fn pack(src: Self, dst: &mut [u8]) -> Result<(), ProgramError> { if dst.len() != Self::LEN { diff --git a/program/src/processor.rs b/program/src/processor.rs index 1508a02..79b93d9 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -35,8 +35,7 @@ impl Processor { let mint_data_len = mint_info.data_len(); let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; - let mut mint_data = mint_info.data.borrow_mut(); - Mint::unpack_unchecked_mut(&mut mint_data, &mut |mint: &mut Mint| { + let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow())?; if mint.is_initialized { return Err(TokenError::AlreadyInUse.into()); } @@ -50,8 +49,9 @@ impl Processor { mint.is_initialized = true; mint.freeze_authority = freeze_authority; + Mint::pack(mint, &mut mint_info.data.borrow_mut())?; + Ok(()) - }) } /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. @@ -63,8 +63,7 @@ impl Processor { let new_account_info_data_len = new_account_info.data_len(); let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; - let mut new_account_data = new_account_info.data.borrow_mut(); - Account::unpack_unchecked_mut(&mut new_account_data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&new_account_info.data.borrow())?; if account.is_initialized() { return Err(TokenError::AlreadyInUse.into()); } @@ -95,8 +94,9 @@ impl Processor { account.amount = 0; }; + Account::pack(account, &mut new_account_info.data.borrow_mut())?; + Ok(()) - }) } /// Processes a [DangerInitializeMultisig](enum.TokenInstruction.html) instruction. @@ -106,10 +106,7 @@ impl Processor { let multisig_info_data_len = multisig_info.data_len(); let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; - let mut multisig_account_data = multisig_info.data.borrow_mut(); - Multisig::unpack_unchecked_mut( - &mut multisig_account_data, - &mut |multisig: &mut Multisig| { + let mut multisig = Multisig::unpack_unchecked(&multisig_info.data.borrow())?; if multisig.is_initialized { return Err(TokenError::AlreadyInUse.into()); } @@ -132,9 +129,9 @@ impl Processor { } multisig.is_initialized = true; + Multisig::pack(multisig, &mut multisig_info.data.borrow_mut())?; + Ok(()) - }, - ) } /// Processes a [Transfer](enum.TokenInstruction.html) instruction. @@ -715,8 +712,7 @@ impl Processor { if program_id == owner_account_info.owner && owner_account_info.data_len() == Multisig::get_packed_len() { - let mut owner_data = owner_account_info.data.borrow_mut(); - Multisig::unpack_mut(&mut owner_data, &mut |multisig: &mut Multisig| { + let multisig = Multisig::unpack(&owner_account_info.data.borrow())?; let mut num_signers = 0; for signer in signers.iter() { if multisig.signers[0..multisig.n as usize].contains(signer.key) { @@ -729,8 +725,7 @@ impl Processor { if num_signers < multisig.m { return Err(ProgramError::MissingRequiredSignature); } - Ok(()) - })?; + return Ok(()); } else if !owner_account_info.is_signer { return Err(ProgramError::MissingRequiredSignature); } @@ -1011,11 +1006,8 @@ mod tests { vec![&mut mint2_account, &mut rent_sysvar], ) .unwrap(); - Mint::unpack_unchecked_mut(&mut mint2_account.data, &mut |mint: &mut Mint| { + let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); assert_eq!(mint.freeze_authority, COption::Some(owner_key)); - Ok(()) - }) - .unwrap(); } #[test] @@ -1223,17 +1215,12 @@ mod tests { .unwrap(); // source-delegate transfer - Account::unpack_unchecked_mut( - &mut account1_info.data.borrow_mut(), - &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); account.amount = 1000; account.delegated_amount = 1000; account.delegate = COption::Some(account1_key); account.owner = owner_key; - Ok(()) - }, - ) - .unwrap(); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( transfer( @@ -1499,11 +1486,9 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut mismatch_account.data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); account.mint = mint2_key; - Ok(()) - }) - .unwrap(); + Account::pack(account, &mut mismatch_account.data).unwrap(); // mint to account do_process_instruction( @@ -1729,11 +1714,8 @@ mod tests { ) .unwrap() } - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 1000); - Ok(()) - }) - .unwrap(); // insufficient funds assert_eq!( @@ -1890,9 +1872,9 @@ mod tests { vec![&mut mint_account, &mut rent_sysvar], ) .unwrap(); - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); assert_eq!( - *mint, + mint, Mint { mint_authority: COption::Some(owner_key), supply: 0, @@ -1901,9 +1883,6 @@ mod tests { freeze_authority: COption::None, } ); - Ok(()) - }) - .unwrap(); // create account do_process_instruction( @@ -1924,11 +1903,8 @@ mod tests { ) .unwrap(); let _ = Mint::unpack(&mut mint_account.data).unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 42); - Ok(()) - }) - .unwrap(); // mint to 2, with incorrect decimals assert_eq!( @@ -1949,11 +1925,8 @@ mod tests { ); let _ = Mint::unpack(&mut mint_account.data).unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 42); - Ok(()) - }) - .unwrap(); // mint to 2 do_process_instruction( @@ -1971,11 +1944,8 @@ mod tests { ) .unwrap(); let _ = Mint::unpack(&mut mint_account.data).unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 84); - Ok(()) - }) - .unwrap(); } #[test] @@ -2478,14 +2448,9 @@ mod tests { .unwrap(); // set close_authority when currently self - Account::unpack_unchecked_mut( - &mut account1_info.data.borrow_mut(), - &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); account.close_authority = COption::Some(account1_key); - Ok(()) - }, - ) - .unwrap(); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( set_authority( @@ -2896,11 +2861,9 @@ mod tests { .unwrap(); // mint_to when mint_authority is account owner - Mint::unpack_unchecked_mut(&mut mint_info.data.borrow_mut(), &mut |mint: &mut Mint| { + let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap(); mint.mint_authority = COption::Some(account1_key); - Ok(()) - }) - .unwrap(); + Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( mint_to( &program_id, @@ -3036,11 +2999,9 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut mismatch_account.data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); account.mint = mint2_key; - Ok(()) - }) - .unwrap(); + Account::pack(account, &mut mismatch_account.data).unwrap(); // mint to do_process_instruction( @@ -3049,16 +3010,10 @@ mod tests { ) .unwrap(); - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); assert_eq!(mint.supply, 42); - Ok(()) - }) - .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 42); - Ok(()) - }) - .unwrap(); // mint to another account to test supply accumulation do_process_instruction( @@ -3067,16 +3022,10 @@ mod tests { ) .unwrap(); - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); assert_eq!(mint.supply, 84); - Ok(()) - }) - .unwrap(); - Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); assert_eq!(account.amount, 42); - Ok(()) - }) - .unwrap(); // missing signer let mut instruction = @@ -3248,14 +3197,9 @@ mod tests { vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], ) .unwrap(); - Account::unpack_unchecked_mut( - &mut account1_info.data.borrow_mut(), - &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); account.owner = mint_key; - Ok(()) - }, - ) - .unwrap(); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], @@ -3284,16 +3228,11 @@ mod tests { vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], ) .unwrap(); - Account::unpack_unchecked_mut( - &mut account1_info.data.borrow_mut(), - &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); account.delegated_amount = 1000; account.delegate = COption::Some(account1_key); account.owner = owner_key; - Ok(()) - }, - ) - .unwrap(); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( burn( &program_id, @@ -3338,16 +3277,11 @@ mod tests { vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], ) .unwrap(); - Account::unpack_unchecked_mut( - &mut account1_info.data.borrow_mut(), - &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); account.delegated_amount = 1000; account.delegate = COption::Some(mint_key); account.owner = owner_key; - Ok(()) - }, - ) - .unwrap(); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], @@ -3464,11 +3398,9 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut mismatch_account.data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); account.mint = mint2_key; - Ok(()) - }) - .unwrap(); + Account::pack(account, &mut mismatch_account.data).unwrap(); // mint to account do_process_instruction( @@ -3534,17 +3466,10 @@ mod tests { ) .unwrap(); - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); assert_eq!(mint.supply, 1000 - 42); - - Ok(()) - }) - .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 1000 - 42); - Ok(()) - }) - .unwrap(); // insufficient funds assert_eq!( @@ -3611,16 +3536,10 @@ mod tests { .unwrap(); // match - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); assert_eq!(mint.supply, 1000 - 42 - 84); - Ok(()) - }) - .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 1000 - 42 - 84); - Ok(()) - }) - .unwrap(); // insufficient funds approved via delegate assert_eq!( @@ -4077,14 +3996,12 @@ mod tests { } let mut lamports = 0; let mut data = vec![0; Multisig::get_packed_len()]; - Multisig::unpack_unchecked_mut(&mut data, &mut |multisig: &mut Multisig| { + let mut multisig = Multisig::unpack_unchecked(&data).unwrap(); multisig.m = MAX_SIGNERS as u8; multisig.n = MAX_SIGNERS as u8; multisig.signers = signer_keys; multisig.is_initialized = true; - Ok(()) - }) - .unwrap(); + Multisig::pack(multisig, &mut data).unwrap(); let owner_account_info = AccountInfo::new( &owner_key, false, @@ -4101,24 +4018,20 @@ mod tests { // 1 of 11 { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); multisig.m = 1; - Ok(()) - }) - .unwrap(); + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); // 2:1 { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); multisig.m = 2; multisig.n = 1; - Ok(()) - }) - .unwrap(); + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } assert_eq!( Err(ProgramError::MissingRequiredSignature), @@ -4127,25 +4040,21 @@ mod tests { // 0:11 { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); multisig.m = 0; multisig.n = 11; - Ok(()) - }) - .unwrap(); + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); // 2:11 but 0 provided { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); multisig.m = 2; multisig.n = 11; - Ok(()) - }) - .unwrap(); + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } assert_eq!( Err(ProgramError::MissingRequiredSignature), @@ -4153,13 +4062,11 @@ mod tests { ); // 2:11 but 1 provided { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); multisig.m = 2; multisig.n = 11; - Ok(()) - }) - .unwrap(); + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } assert_eq!( Err(ProgramError::MissingRequiredSignature), @@ -4168,26 +4075,22 @@ mod tests { // 2:11, 2 from middle provided { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); multisig.m = 2; multisig.n = 11; - Ok(()) - }) - .unwrap(); + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[5..7]) .unwrap(); // 11:11, one is not a signer { - let mut data_ref_mut = owner_account_info.data.borrow_mut(); - Multisig::unpack_unchecked_mut(&mut data_ref_mut, &mut |multisig: &mut Multisig| { + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); multisig.m = 2; // TODO 11? multisig.n = 11; - Ok(()) - }) - .unwrap(); + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } signers[5].is_signer = false; assert_eq!( @@ -4261,15 +4164,10 @@ mod tests { .unwrap(); // source-close-authority close - Account::unpack_unchecked_mut( - &mut account1_info.data.borrow_mut(), - &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); account.close_authority = COption::Some(account1_key); account.owner = owner_key; - Ok(()) - }, - ) - .unwrap(); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( close_account( &program_id, @@ -4357,11 +4255,8 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 42); - Ok(()) - }) - .unwrap(); // initialize native account do_process_instruction( @@ -4380,12 +4275,9 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); assert!(account.is_native()); assert_eq!(account.amount, 42); - Ok(()) - }) - .unwrap(); // close non-native account with balance assert_eq!( @@ -4433,11 +4325,8 @@ mod tests { .unwrap(); assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 0); - Ok(()) - }) - .unwrap(); // fund and initialize new non-native account to test close authority let account_key = pubkey_rand(); @@ -4503,11 +4392,8 @@ mod tests { .unwrap(); assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 0); - Ok(()) - }) - .unwrap(); // close native account do_process_instruction( @@ -4519,7 +4405,7 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); assert!(account.is_native()); assert_eq!(account_account.lamports, 0); assert_eq!(account.amount, 0); @@ -4527,9 +4413,6 @@ mod tests { account3_account.lamports, 3 * account_minimum_balance() + 2 + 42 ); - Ok(()) - }) - .unwrap(); } #[test] @@ -4572,12 +4455,9 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert!(account.is_native()); assert_eq!(account.amount, 40); - Ok(()) - }) - .unwrap(); // initialize native account do_process_instruction( @@ -4596,12 +4476,9 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); assert!(account.is_native()); assert_eq!(account.amount, 0); - Ok(()) - }) - .unwrap(); // mint_to unsupported assert_eq!( @@ -4690,19 +4567,13 @@ mod tests { ) .unwrap(); assert_eq!(account_account.lamports, account_minimum_balance()); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert!(account.is_native()); assert_eq!(account.amount, 0); - Ok(()) - }) - .unwrap(); assert_eq!(account2_account.lamports, account_minimum_balance() + 40); - Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); assert!(account.is_native()); assert_eq!(account.amount, 40); - Ok(()) - }) - .unwrap(); // close native account do_process_instruction( @@ -4716,12 +4587,9 @@ mod tests { .unwrap(); assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert!(account.is_native()); assert_eq!(account.amount, 0); - Ok(()) - }) - .unwrap(); } #[test] @@ -4799,11 +4667,8 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX); - Ok(()) - }) - .unwrap(); // attempt to mint one more to account assert_eq!( @@ -4825,11 +4690,8 @@ mod tests { ], ) ); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX); - Ok(()) - }) - .unwrap(); // atttempt to mint one more to the other account assert_eq!( @@ -4858,11 +4720,8 @@ mod tests { vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX - 100); - Ok(()) - }) - .unwrap(); do_process_instruction( mint_to( @@ -4881,18 +4740,13 @@ mod tests { ], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX); - Ok(()) - }) - .unwrap(); // manipulate account balance to attempt overflow transfer - Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); account.amount = 1; - Ok(()) - }) - .unwrap(); + Account::pack(account, &mut account2_account.data).unwrap(); assert_eq!( Err(TokenError::Overflow.into()), @@ -4976,11 +4830,9 @@ mod tests { .unwrap(); // no transfer if either account is frozen - Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); account.state = AccountState::Frozen; - Ok(()) - }) - .unwrap(); + Account::pack(account, &mut account2_account.data).unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), do_process_instruction( @@ -5001,16 +4853,12 @@ mod tests { ) ); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); account.state = AccountState::Initialized; - Ok(()) - }) - .unwrap(); - Account::unpack_unchecked_mut(&mut account2_account.data, &mut |account: &mut Account| { + Account::pack(account, &mut account_account.data).unwrap(); + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); account.state = AccountState::Frozen; - Ok(()) - }) - .unwrap(); + Account::pack(account, &mut account2_account.data).unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), do_process_instruction( @@ -5032,11 +4880,9 @@ mod tests { ); // no approve if account is frozen - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); account.state = AccountState::Frozen; - Ok(()) - }) - .unwrap(); + Account::pack(account, &mut account_account.data).unwrap(); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); assert_eq!( @@ -5060,12 +4906,10 @@ mod tests { ); // no revoke if account is frozen - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); account.delegate = COption::Some(delegate_key); account.delegated_amount = 100; - Ok(()) - }) - .unwrap(); + Account::pack(account, &mut account_account.data).unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), do_process_instruction( @@ -5161,14 +5005,9 @@ mod tests { .unwrap(); // thaw where mint freeze_authority is account - Account::unpack_unchecked_mut( - &mut account1_info.data.borrow_mut(), - &mut |account: &mut Account| { + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); account.state = AccountState::Frozen; - Ok(()) - }, - ) - .unwrap(); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), vec![ @@ -5236,11 +5075,9 @@ mod tests { ); // missing freeze_authority - Mint::unpack_unchecked_mut(&mut mint_account.data, &mut |mint: &mut Mint| { + let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); mint.freeze_authority = COption::Some(owner_key); - Ok(()) - }) - .unwrap(); + Mint::pack(mint, &mut mint_account.data).unwrap(); assert_eq!( Err(TokenError::OwnerMismatch.into()), do_process_instruction( @@ -5264,11 +5101,8 @@ mod tests { vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.state, AccountState::Frozen); - Ok(()) - }) - .unwrap(); // check explicit freeze assert_eq!( @@ -5294,10 +5128,7 @@ mod tests { vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); - Account::unpack_unchecked_mut(&mut account_account.data, &mut |account: &mut Account| { + let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.state, AccountState::Initialized); - Ok(()) - }) - .unwrap(); } } From 0a276fd90ba6d3db5eb54581348d9ad9cc7152f8 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 12:58:26 -0700 Subject: [PATCH 074/335] backport #448 to v2 --- program/src/error.rs | 3 --- program/src/pack.rs | 3 +-- program/src/processor.rs | 7 +++---- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/program/src/error.rs b/program/src/error.rs index 32cd9d2..e56fde6 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -34,9 +34,6 @@ pub enum TokenError { /// Invalid number of required signers. #[error("Invalid number of required signers")] InvalidNumberOfRequiredSigners, - /// State is uninitialized. - #[error("State is unititialized")] - UninitializedState, /// Instruction does not support native tokens #[error("Instruction does not support native tokens")] NativeNotSupported, diff --git a/program/src/pack.rs b/program/src/pack.rs index 106b51b..7c0f355 100644 --- a/program/src/pack.rs +++ b/program/src/pack.rs @@ -1,6 +1,5 @@ //! State transition types -use crate::error::TokenError; use solana_sdk::program_error::ProgramError; /// Check is a token state is initialized @@ -35,7 +34,7 @@ pub trait Pack: Sealed { if value.is_initialized() { Ok(value) } else { - Err(TokenError::UninitializedState.into()) + Err(ProgramError::UninitializedAccount) } } diff --git a/program/src/processor.rs b/program/src/processor.rs index 79b93d9..7633636 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -754,7 +754,6 @@ impl PrintProgramError for TokenError { TokenError::InvalidNumberOfRequiredSigners => { info!("Error: Invalid number of required signers") } - TokenError::UninitializedState => info!("Error: State is uninitialized"), TokenError::NativeNotSupported => { info!("Error: Instruction does not support native tokens") } @@ -2511,7 +2510,7 @@ mod tests { // invalid account assert_eq!( - Err(TokenError::UninitializedState.into()), + Err(ProgramError::UninitializedAccount), do_process_instruction( set_authority( &program_id, @@ -3063,7 +3062,7 @@ mod tests { // uninitialized destination account assert_eq!( - Err(TokenError::UninitializedState.into()), + Err(ProgramError::UninitializedAccount), do_process_instruction( mint_to( &program_id, @@ -4218,7 +4217,7 @@ mod tests { // uninitialized assert_eq!( - Err(TokenError::UninitializedState.into()), + Err(ProgramError::UninitializedAccount), do_process_instruction( close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), vec![ From d8b29e9bf05b15e49de324473fd16d3219d40ad3 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 13:08:17 -0700 Subject: [PATCH 075/335] backport #479 to v2 --- program/src/instruction.rs | 19 ++++++------- program/src/processor.rs | 55 +++++++++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 2e2d990..5c8e1b0 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -56,14 +56,11 @@ pub enum TokenInstruction { InitializeAccount, /// Initializes a multisignature account with N provided signers. /// - /// Warning, this instruction is compromised: - /// https://github.com/solana-labs/solana-program-library/issues/477 - /// /// Multisignature accounts can used in place of any single owner/delegate accounts in any /// token instruction that require an owner/delegate to be present. The variant field represents the /// number of signers (M) required to validate this multisignature account. /// - /// The `DangerInitializeMultisig` instruction requires no signers and MUST be included within + /// The `InitializeMultisig` instruction requires no signers and MUST be included within /// the same Transaction as the system program's `CreateInstruction` that creates the account /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. /// @@ -72,7 +69,7 @@ pub enum TokenInstruction { /// 0. `[writable]` The multisignature account to initialize. /// 1. `[]` Rent sysvar /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. - DangerInitializeMultisig { + InitializeMultisig { /// The number of signers (M) required to validate this multisignature account. m: u8, }, @@ -353,7 +350,7 @@ impl TokenInstruction { 1 => Self::InitializeAccount, 2 => { let &m = rest.get(0).ok_or(InvalidInstruction)?; - Self::DangerInitializeMultisig { m } + Self::InitializeMultisig { m } } 3 | 4 | 7 | 8 => { let amount = rest @@ -449,7 +446,7 @@ impl TokenInstruction { Self::pack_pubkey_option(freeze_authority, &mut buf); } Self::InitializeAccount => buf.push(1), - &Self::DangerInitializeMultisig { m } => { + &Self::InitializeMultisig { m } => { buf.push(2); buf.push(m); } @@ -624,8 +621,8 @@ pub fn initialize_account( }) } -/// Creates a `DangerInitializeMultisig` instruction. -pub fn danger_initialize_multisig( +/// Creates a `InitializeMultisig` instruction. +pub fn initialize_multisig( token_program_id: &Pubkey, multisig_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], @@ -637,7 +634,7 @@ pub fn danger_initialize_multisig( { return Err(ProgramError::MissingRequiredSignature); } - let data = TokenInstruction::DangerInitializeMultisig { m }.pack(); + let data = TokenInstruction::InitializeMultisig { m }.pack(); let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*multisig_pubkey, false)); @@ -1083,7 +1080,7 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); - let check = TokenInstruction::DangerInitializeMultisig { m: 1 }; + let check = TokenInstruction::InitializeMultisig { m: 1 }; let packed = check.pack(); let expect = Vec::from([2u8, 1]); assert_eq!(packed, expect); diff --git a/program/src/processor.rs b/program/src/processor.rs index 7633636..a4ce7a0 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -4,7 +4,7 @@ use crate::{ error::TokenError, - instruction::{is_valid_signer_index, AuthorityType, TokenInstruction}, + instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, option::COption, pack::{IsInitialized, Pack}, state::{Account, AccountState, Mint, Multisig}, @@ -99,8 +99,8 @@ impl Processor { Ok(()) } - /// Processes a [DangerInitializeMultisig](enum.TokenInstruction.html) instruction. - pub fn process_danger_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { + /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. + pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let multisig_info = next_account_info(account_info_iter)?; let multisig_info_data_len = multisig_info.data_len(); @@ -637,9 +637,9 @@ impl Processor { info!("Instruction: InitializeAccount"); Self::process_initialize_account(accounts) } - TokenInstruction::DangerInitializeMultisig { m } => { - info!("Instruction: DangerInitializeMultisig"); - Self::process_danger_initialize_multisig(accounts, m) + TokenInstruction::InitializeMultisig { m } => { + info!("Instruction: InitializeMultisig"); + Self::process_initialize_multisig(accounts, m) } TokenInstruction::Transfer { amount } => { info!("Instruction: Transfer"); @@ -714,14 +714,18 @@ impl Processor { { let multisig = Multisig::unpack(&owner_account_info.data.borrow())?; let mut num_signers = 0; + let mut matched = [false; MAX_SIGNERS]; for signer in signers.iter() { - if multisig.signers[0..multisig.n as usize].contains(signer.key) { + for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() { + if key == signer.key && !matched[position] { if !signer.is_signer { return Err(ProgramError::MissingRequiredSignature); } + matched[position] = true; num_signers += 1; } } + } if num_signers < multisig.m { return Err(ProgramError::MissingRequiredSignature); } @@ -3600,8 +3604,7 @@ mod tests { assert_eq!( Err(TokenError::NotRentExempt.into()), do_process_instruction( - danger_initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1) - .unwrap(), + initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), vec![ &mut multisig_account, &mut rent_sysvar, @@ -3615,7 +3618,7 @@ mod tests { // single signer let account_info_iter = &mut signer_accounts.iter_mut(); do_process_instruction( - danger_initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), vec![ &mut multisig_account, &mut rent_sysvar, @@ -3627,7 +3630,7 @@ mod tests { // multiple signer let account_info_iter = &mut signer_accounts.iter_mut(); do_process_instruction( - danger_initialize_multisig( + initialize_multisig( &program_id, &multisig_delegate_key, &signer_key_refs, @@ -4087,7 +4090,7 @@ mod tests { { let mut multisig = Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; // TODO 11? + multisig.m = 11; multisig.n = 11; Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } @@ -4097,6 +4100,34 @@ mod tests { Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) ); signers[5].is_signer = true; + + // 11:11, single signer signs multiple times + { + let mut signer_lamports = 0; + let mut signer_data = vec![]; + let signers = vec![ + AccountInfo::new( + &signer_keys[5], + true, + false, + &mut signer_lamports, + &mut signer_data, + &program_id, + false, + Epoch::default(), + ); + MAX_SIGNERS + 1 + ]; + let mut multisig = + Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); + multisig.m = 11; + multisig.n = 11; + Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers) + ); + } } #[test] From e167aacd49e60f3c173f540b93701512b9dec888 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 13:13:56 -0700 Subject: [PATCH 076/335] backport #484 to v2 --- program/Cargo.toml | 2 +- program/src/instruction.rs | 3 +- program/src/lib.rs | 2 - program/src/option.rs | 980 ------------------------------------- program/src/pack.rs | 57 --- program/src/processor.rs | 4 +- program/src/state.rs | 15 +- 7 files changed, 12 insertions(+), 1051 deletions(-) delete mode 100644 program/src/option.rs delete mode 100644 program/src/pack.rs diff --git a/program/Cargo.toml b/program/Cargo.toml index 16e174f..9be3b68 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,7 +21,7 @@ default = ["solana-sdk/default"] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.11", default-features = false, optional = true } +solana-sdk = { version = "1.3.12", default-features = false, optional = true } thiserror = "1.0" arrayref = "0.3.6" num_enum = "0.5.1" diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 5c8e1b0..ae01523 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -1,9 +1,10 @@ //! Instruction types -use crate::{error::TokenError, option::COption}; +use crate::error::TokenError; use solana_sdk::{ instruction::{AccountMeta, Instruction}, program_error::ProgramError, + program_option::COption, pubkey::Pubkey, sysvar, }; diff --git a/program/src/lib.rs b/program/src/lib.rs index 52dc77f..6e7108f 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -7,8 +7,6 @@ pub mod entrypoint; pub mod error; pub mod instruction; pub mod native_mint; -pub mod option; -pub mod pack; pub mod processor; pub mod state; diff --git a/program/src/option.rs b/program/src/option.rs deleted file mode 100644 index 01ba5df..0000000 --- a/program/src/option.rs +++ /dev/null @@ -1,980 +0,0 @@ -//! A C representation of Rust's `std::option::Option` used accross the FFI -//! boundary for Solana program interfaces -//! -//! This implementation mostly matches `std::option` except iterators since the iteration -//! trait requires returning `std::option::Option` - -use std::{ - convert, mem, - ops::{Deref, DerefMut}, -}; - -/// A C representation of Rust's `std::option::Option` -#[repr(C)] -#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] -pub enum COption { - /// No value - None, - /// Some value `T` - Some(T), -} - -///////////////////////////////////////////////////////////////////////////// -// Type implementation -///////////////////////////////////////////////////////////////////////////// - -impl COption { - ///////////////////////////////////////////////////////////////////////// - // Querying the contained values - ///////////////////////////////////////////////////////////////////////// - - /// Returns `true` if the option is a [`COption::Some`] value. - /// - /// # Examples - /// - /// ```ignore - /// let x: COption = COption::Some(2); - /// assert_eq!(x.is_some(), true); - /// - /// let x: COption = COption::None; - /// assert_eq!(x.is_some(), false); - /// ``` - /// - /// [`COption::Some`]: #variant.COption::Some - #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] - #[inline] - pub fn is_some(&self) -> bool { - match *self { - COption::Some(_) => true, - COption::None => false, - } - } - - /// Returns `true` if the option is a [`COption::None`] value. - /// - /// # Examples - /// - /// ```ignore - /// let x: COption = COption::Some(2); - /// assert_eq!(x.is_none(), false); - /// - /// let x: COption = COption::None; - /// assert_eq!(x.is_none(), true); - /// ``` - /// - /// [`COption::None`]: #variant.COption::None - #[must_use = "if you intended to assert that this doesn't have a value, consider \ - `.and_then(|| panic!(\"`COption` had a value when expected `COption::None`\"))` instead"] - #[inline] - pub fn is_none(&self) -> bool { - !self.is_some() - } - - /// Returns `true` if the option is a [`COption::Some`] value containing the given value. - /// - /// # Examples - /// - /// ```ignore - /// #![feature(option_result_contains)] - /// - /// let x: COption = COption::Some(2); - /// assert_eq!(x.contains(&2), true); - /// - /// let x: COption = COption::Some(3); - /// assert_eq!(x.contains(&2), false); - /// - /// let x: COption = COption::None; - /// assert_eq!(x.contains(&2), false); - /// ``` - #[must_use] - #[inline] - pub fn contains(&self, x: &U) -> bool - where - U: PartialEq, - { - match self { - COption::Some(y) => x == y, - COption::None => false, - } - } - - ///////////////////////////////////////////////////////////////////////// - // Adapter for working with references - ///////////////////////////////////////////////////////////////////////// - - /// Converts from `&COption` to `COption<&T>`. - /// - /// # Examples - /// - /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, preserving the original. - /// The [`map`] method takes the `self` argument by value, consuming the original, - /// so this technique uses `as_ref` to first take an `COption` to a reference - /// to the value inside the original. - /// - /// [`map`]: enum.COption.html#method.map - /// [`String`]: ../../std/string/struct.String.html - /// [`usize`]: ../../std/primitive.usize.html - /// - /// ```ignore - /// let text: COption = COption::Some("Hello, world!".to_string()); - /// // First, cast `COption` to `COption<&String>` with `as_ref`, - /// // then consume *that* with `map`, leaving `text` on the stack. - /// let text_length: COption = text.as_ref().map(|s| s.len()); - /// println!("still can print text: {:?}", text); - /// ``` - #[inline] - pub fn as_ref(&self) -> COption<&T> { - match *self { - COption::Some(ref x) => COption::Some(x), - COption::None => COption::None, - } - } - - /// Converts from `&mut COption` to `COption<&mut T>`. - /// - /// # Examples - /// - /// ```ignore - /// let mut x = COption::Some(2); - /// match x.as_mut() { - /// COption::Some(v) => *v = 42, - /// COption::None => {}, - /// } - /// assert_eq!(x, COption::Some(42)); - /// ``` - #[inline] - pub fn as_mut(&mut self) -> COption<&mut T> { - match *self { - COption::Some(ref mut x) => COption::Some(x), - COption::None => COption::None, - } - } - - ///////////////////////////////////////////////////////////////////////// - // Getting to contained values - ///////////////////////////////////////////////////////////////////////// - - /// Unwraps an option, yielding the content of a [`COption::Some`]. - /// - /// # Panics - /// - /// Panics if the value is a [`COption::None`] with a custom panic message provided by - /// `msg`. - /// - /// [`COption::Some`]: #variant.COption::Some - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("value"); - /// assert_eq!(x.expect("the world is ending"), "value"); - /// ``` - /// - /// ```ignore{.should_panic} - /// let x: COption<&str> = COption::None; - /// x.expect("the world is ending"); // panics with `the world is ending` - /// ``` - #[inline] - pub fn expect(self, msg: &str) -> T { - match self { - COption::Some(val) => val, - COption::None => expect_failed(msg), - } - } - - /// Moves the value `v` out of the `COption` if it is [`COption::Some(v)`]. - /// - /// In general, because this function may panic, its use is discouraged. - /// Instead, prefer to use pattern matching and handle the [`COption::None`] - /// case explicitly. - /// - /// # Panics - /// - /// Panics if the self value equals [`COption::None`]. - /// - /// [`COption::Some(v)`]: #variant.COption::Some - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("air"); - /// assert_eq!(x.unwrap(), "air"); - /// ``` - /// - /// ```ignore{.should_panic} - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.unwrap(), "air"); // fails - /// ``` - #[inline] - pub fn unwrap(self) -> T { - match self { - COption::Some(val) => val, - COption::None => panic!("called `COption::unwrap()` on a `COption::None` value"), - } - } - - /// Returns the contained value or a default. - /// - /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing - /// the result of a function call, it is recommended to use [`unwrap_or_else`], - /// which is lazily evaluated. - /// - /// [`unwrap_or_else`]: #method.unwrap_or_else - /// - /// # Examples - /// - /// ```ignore - /// assert_eq!(COption::Some("car").unwrap_or("bike"), "car"); - /// assert_eq!(COption::None.unwrap_or("bike"), "bike"); - /// ``` - #[inline] - pub fn unwrap_or(self, def: T) -> T { - match self { - COption::Some(x) => x, - COption::None => def, - } - } - - /// Returns the contained value or computes it from a closure. - /// - /// # Examples - /// - /// ```ignore - /// let k = 10; - /// assert_eq!(COption::Some(4).unwrap_or_else(|| 2 * k), 4); - /// assert_eq!(COption::None.unwrap_or_else(|| 2 * k), 20); - /// ``` - #[inline] - pub fn unwrap_or_else T>(self, f: F) -> T { - match self { - COption::Some(x) => x, - COption::None => f(), - } - } - - ///////////////////////////////////////////////////////////////////////// - // Transforming contained values - ///////////////////////////////////////////////////////////////////////// - - /// Maps an `COption` to `COption` by applying a function to a contained value. - /// - /// # Examples - /// - /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, consuming the original: - /// - /// [`String`]: ../../std/string/struct.String.html - /// [`usize`]: ../../std/primitive.usize.html - /// - /// ```ignore - /// let maybe_some_string = COption::Some(String::from("Hello, World!")); - /// // `COption::map` takes self *by value*, consuming `maybe_some_string` - /// let maybe_some_len = maybe_some_string.map(|s| s.len()); - /// - /// assert_eq!(maybe_some_len, COption::Some(13)); - /// ``` - #[inline] - pub fn map U>(self, f: F) -> COption { - match self { - COption::Some(x) => COption::Some(f(x)), - COption::None => COption::None, - } - } - - /// Applies a function to the contained value (if any), - /// or returns the provided default (if not). - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("foo"); - /// assert_eq!(x.map_or(42, |v| v.len()), 3); - /// - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.map_or(42, |v| v.len()), 42); - /// ``` - #[inline] - pub fn map_or U>(self, default: U, f: F) -> U { - match self { - COption::Some(t) => f(t), - COption::None => default, - } - } - - /// Applies a function to the contained value (if any), - /// or computes a default (if not). - /// - /// # Examples - /// - /// ```ignore - /// let k = 21; - /// - /// let x = COption::Some("foo"); - /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3); - /// - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42); - /// ``` - #[inline] - pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { - match self { - COption::Some(t) => f(t), - COption::None => default(), - } - } - - /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to - /// [`Ok(v)`] and [`COption::None`] to [`Err(err)`]. - /// - /// Arguments passed to `ok_or` are eagerly evaluated; if you are passing the - /// result of a function call, it is recommended to use [`ok_or_else`], which is - /// lazily evaluated. - /// - /// [`Result`]: ../../std/result/enum.Result.html - /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Err(err)`]: ../../std/result/enum.Result.html#variant.Err - /// [`COption::None`]: #variant.COption::None - /// [`COption::Some(v)`]: #variant.COption::Some - /// [`ok_or_else`]: #method.ok_or_else - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("foo"); - /// assert_eq!(x.ok_or(0), Ok("foo")); - /// - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.ok_or(0), Err(0)); - /// ``` - #[inline] - pub fn ok_or(self, err: E) -> Result { - match self { - COption::Some(v) => Ok(v), - COption::None => Err(err), - } - } - - /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to - /// [`Ok(v)`] and [`COption::None`] to [`Err(err())`]. - /// - /// [`Result`]: ../../std/result/enum.Result.html - /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Err(err())`]: ../../std/result/enum.Result.html#variant.Err - /// [`COption::None`]: #variant.COption::None - /// [`COption::Some(v)`]: #variant.COption::Some - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some("foo"); - /// assert_eq!(x.ok_or_else(|| 0), Ok("foo")); - /// - /// let x: COption<&str> = COption::None; - /// assert_eq!(x.ok_or_else(|| 0), Err(0)); - /// ``` - #[inline] - pub fn ok_or_else E>(self, err: F) -> Result { - match self { - COption::Some(v) => Ok(v), - COption::None => Err(err()), - } - } - - ///////////////////////////////////////////////////////////////////////// - // Boolean operations on the values, eager and lazy - ///////////////////////////////////////////////////////////////////////// - - /// Returns [`COption::None`] if the option is [`COption::None`], otherwise returns `optb`. - /// - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some(2); - /// let y: COption<&str> = COption::None; - /// assert_eq!(x.and(y), COption::None); - /// - /// let x: COption = COption::None; - /// let y = COption::Some("foo"); - /// assert_eq!(x.and(y), COption::None); - /// - /// let x = COption::Some(2); - /// let y = COption::Some("foo"); - /// assert_eq!(x.and(y), COption::Some("foo")); - /// - /// let x: COption = COption::None; - /// let y: COption<&str> = COption::None; - /// assert_eq!(x.and(y), COption::None); - /// ``` - #[inline] - pub fn and(self, optb: COption) -> COption { - match self { - COption::Some(_) => optb, - COption::None => COption::None, - } - } - - /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `f` with the - /// wrapped value and returns the result. - /// - /// COption::Some languages call this operation flatmap. - /// - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// fn sq(x: u32) -> COption { COption::Some(x * x) } - /// fn nope(_: u32) -> COption { COption::None } - /// - /// assert_eq!(COption::Some(2).and_then(sq).and_then(sq), COption::Some(16)); - /// assert_eq!(COption::Some(2).and_then(sq).and_then(nope), COption::None); - /// assert_eq!(COption::Some(2).and_then(nope).and_then(sq), COption::None); - /// assert_eq!(COption::None.and_then(sq).and_then(sq), COption::None); - /// ``` - #[inline] - pub fn and_then COption>(self, f: F) -> COption { - match self { - COption::Some(x) => f(x), - COption::None => COption::None, - } - } - - /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `predicate` - /// with the wrapped value and returns: - /// - /// - [`COption::Some(t)`] if `predicate` returns `true` (where `t` is the wrapped - /// value), and - /// - [`COption::None`] if `predicate` returns `false`. - /// - /// This function works similar to [`Iterator::filter()`]. You can imagine - /// the `COption` being an iterator over one or zero elements. `filter()` - /// lets you decide which elements to keep. - /// - /// # Examples - /// - /// ```ignore - /// fn is_even(n: &i32) -> bool { - /// n % 2 == 0 - /// } - /// - /// assert_eq!(COption::None.filter(is_even), COption::None); - /// assert_eq!(COption::Some(3).filter(is_even), COption::None); - /// assert_eq!(COption::Some(4).filter(is_even), COption::Some(4)); - /// ``` - /// - /// [`COption::None`]: #variant.COption::None - /// [`COption::Some(t)`]: #variant.COption::Some - /// [`Iterator::filter()`]: ../../std/iter/trait.Iterator.html#method.filter - #[inline] - pub fn filter bool>(self, predicate: P) -> Self { - if let COption::Some(x) = self { - if predicate(&x) { - return COption::Some(x); - } - } - COption::None - } - - /// Returns the option if it contains a value, otherwise returns `optb`. - /// - /// Arguments passed to `or` are eagerly evaluated; if you are passing the - /// result of a function call, it is recommended to use [`or_else`], which is - /// lazily evaluated. - /// - /// [`or_else`]: #method.or_else - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some(2); - /// let y = COption::None; - /// assert_eq!(x.or(y), COption::Some(2)); - /// - /// let x = COption::None; - /// let y = COption::Some(100); - /// assert_eq!(x.or(y), COption::Some(100)); - /// - /// let x = COption::Some(2); - /// let y = COption::Some(100); - /// assert_eq!(x.or(y), COption::Some(2)); - /// - /// let x: COption = COption::None; - /// let y = COption::None; - /// assert_eq!(x.or(y), COption::None); - /// ``` - #[inline] - pub fn or(self, optb: COption) -> COption { - match self { - COption::Some(_) => self, - COption::None => optb, - } - } - - /// Returns the option if it contains a value, otherwise calls `f` and - /// returns the result. - /// - /// # Examples - /// - /// ```ignore - /// fn nobody() -> COption<&'static str> { COption::None } - /// fn vikings() -> COption<&'static str> { COption::Some("vikings") } - /// - /// assert_eq!(COption::Some("barbarians").or_else(vikings), COption::Some("barbarians")); - /// assert_eq!(COption::None.or_else(vikings), COption::Some("vikings")); - /// assert_eq!(COption::None.or_else(nobody), COption::None); - /// ``` - #[inline] - pub fn or_else COption>(self, f: F) -> COption { - match self { - COption::Some(_) => self, - COption::None => f(), - } - } - - /// Returns [`COption::Some`] if exactly one of `self`, `optb` is [`COption::Some`], otherwise returns [`COption::None`]. - /// - /// [`COption::Some`]: #variant.COption::Some - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let x = COption::Some(2); - /// let y: COption = COption::None; - /// assert_eq!(x.xor(y), COption::Some(2)); - /// - /// let x: COption = COption::None; - /// let y = COption::Some(2); - /// assert_eq!(x.xor(y), COption::Some(2)); - /// - /// let x = COption::Some(2); - /// let y = COption::Some(2); - /// assert_eq!(x.xor(y), COption::None); - /// - /// let x: COption = COption::None; - /// let y: COption = COption::None; - /// assert_eq!(x.xor(y), COption::None); - /// ``` - #[inline] - pub fn xor(self, optb: COption) -> COption { - match (self, optb) { - (COption::Some(a), COption::None) => COption::Some(a), - (COption::None, COption::Some(b)) => COption::Some(b), - _ => COption::None, - } - } - - ///////////////////////////////////////////////////////////////////////// - // Entry-like operations to insert if COption::None and return a reference - ///////////////////////////////////////////////////////////////////////// - - /// Inserts `v` into the option if it is [`COption::None`], then - /// returns a mutable reference to the contained value. - /// - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let mut x = COption::None; - /// - /// { - /// let y: &mut u32 = x.get_or_insert(5); - /// assert_eq!(y, &5); - /// - /// *y = 7; - /// } - /// - /// assert_eq!(x, COption::Some(7)); - /// ``` - #[inline] - pub fn get_or_insert(&mut self, v: T) -> &mut T { - self.get_or_insert_with(|| v) - } - - /// Inserts a value computed from `f` into the option if it is [`COption::None`], then - /// returns a mutable reference to the contained value. - /// - /// [`COption::None`]: #variant.COption::None - /// - /// # Examples - /// - /// ```ignore - /// let mut x = COption::None; - /// - /// { - /// let y: &mut u32 = x.get_or_insert_with(|| 5); - /// assert_eq!(y, &5); - /// - /// *y = 7; - /// } - /// - /// assert_eq!(x, COption::Some(7)); - /// ``` - #[inline] - pub fn get_or_insert_with T>(&mut self, f: F) -> &mut T { - if let COption::None = *self { - *self = COption::Some(f()) - } - - match *self { - COption::Some(ref mut v) => v, - COption::None => unreachable!(), - } - } - - ///////////////////////////////////////////////////////////////////////// - // Misc - ///////////////////////////////////////////////////////////////////////// - - /// Replaces the actual value in the option by the value given in parameter, - /// returning the old value if present, - /// leaving a [`COption::Some`] in its place without deinitializing either one. - /// - /// [`COption::Some`]: #variant.COption::Some - /// - /// # Examples - /// - /// ```ignore - /// let mut x = COption::Some(2); - /// let old = x.replace(5); - /// assert_eq!(x, COption::Some(5)); - /// assert_eq!(old, COption::Some(2)); - /// - /// let mut x = COption::None; - /// let old = x.replace(3); - /// assert_eq!(x, COption::Some(3)); - /// assert_eq!(old, COption::None); - /// ``` - #[inline] - pub fn replace(&mut self, value: T) -> COption { - mem::replace(self, COption::Some(value)) - } -} - -impl COption<&T> { - /// Maps an `COption<&T>` to an `COption` by copying the contents of the - /// option. - /// - /// # Examples - /// - /// ```ignore - /// let x = 12; - /// let opt_x = COption::Some(&x); - /// assert_eq!(opt_x, COption::Some(&12)); - /// let copied = opt_x.copied(); - /// assert_eq!(copied, COption::Some(12)); - /// ``` - pub fn copied(self) -> COption { - self.map(|&t| t) - } -} - -impl COption<&mut T> { - /// Maps an `COption<&mut T>` to an `COption` by copying the contents of the - /// option. - /// - /// # Examples - /// - /// ```ignore - /// let mut x = 12; - /// let opt_x = COption::Some(&mut x); - /// assert_eq!(opt_x, COption::Some(&mut 12)); - /// let copied = opt_x.copied(); - /// assert_eq!(copied, COption::Some(12)); - /// ``` - pub fn copied(self) -> COption { - self.map(|&mut t| t) - } -} - -impl COption<&T> { - /// Maps an `COption<&T>` to an `COption` by cloning the contents of the - /// option. - /// - /// # Examples - /// - /// ```ignore - /// let x = 12; - /// let opt_x = COption::Some(&x); - /// assert_eq!(opt_x, COption::Some(&12)); - /// let cloned = opt_x.cloned(); - /// assert_eq!(cloned, COption::Some(12)); - /// ``` - pub fn cloned(self) -> COption { - self.map(|t| t.clone()) - } -} - -impl COption<&mut T> { - /// Maps an `COption<&mut T>` to an `COption` by cloning the contents of the - /// option. - /// - /// # Examples - /// - /// ```ignore - /// let mut x = 12; - /// let opt_x = COption::Some(&mut x); - /// assert_eq!(opt_x, COption::Some(&mut 12)); - /// let cloned = opt_x.cloned(); - /// assert_eq!(cloned, COption::Some(12)); - /// ``` - pub fn cloned(self) -> COption { - self.map(|t| t.clone()) - } -} - -impl COption { - /// Returns the contained value or a default - /// - /// Consumes the `self` argument then, if [`COption::Some`], returns the contained - /// value, otherwise if [`COption::None`], returns the [default value] for that - /// type. - /// - /// # Examples - /// - /// Converts a string to an integer, turning poorly-formed strings - /// into 0 (the default value for integers). [`parse`] converts - /// a string to any other type that implements [`FromStr`], returning - /// [`COption::None`] on error. - /// - /// ```ignore - /// let good_year_from_input = "1909"; - /// let bad_year_from_input = "190blarg"; - /// let good_year = good_year_from_input.parse().ok().unwrap_or_default(); - /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default(); - /// - /// assert_eq!(1909, good_year); - /// assert_eq!(0, bad_year); - /// ``` - /// - /// [`COption::Some`]: #variant.COption::Some - /// [`COption::None`]: #variant.COption::None - /// [default value]: ../default/trait.Default.html#tymethod.default - /// [`parse`]: ../../std/primitive.str.html#method.parse - /// [`FromStr`]: ../../std/str/trait.FromStr.html - #[inline] - pub fn unwrap_or_default(self) -> T { - match self { - COption::Some(x) => x, - COption::None => Default::default(), - } - } -} - -impl COption { - /// Converts from `COption` (or `&COption`) to `COption<&T::Target>`. - /// - /// Leaves the original COption in-place, creating a new one with a reference - /// to the original one, additionally coercing the contents via [`Deref`]. - /// - /// [`Deref`]: ../../std/ops/trait.Deref.html - /// - /// # Examples - /// - /// ```ignore - /// #![feature(inner_deref)] - /// - /// let x: COption = COption::Some("hey".to_owned()); - /// assert_eq!(x.as_deref(), COption::Some("hey")); - /// - /// let x: COption = COption::None; - /// assert_eq!(x.as_deref(), COption::None); - /// ``` - pub fn as_deref(&self) -> COption<&T::Target> { - self.as_ref().map(|t| t.deref()) - } -} - -impl COption { - /// Converts from `COption` (or `&mut COption`) to `COption<&mut T::Target>`. - /// - /// Leaves the original `COption` in-place, creating a new one containing a mutable reference to - /// the inner type's `Deref::Target` type. - /// - /// # Examples - /// - /// ```ignore - /// #![feature(inner_deref)] - /// - /// let mut x: COption = COption::Some("hey".to_owned()); - /// assert_eq!(x.as_deref_mut().map(|x| { - /// x.make_ascii_uppercase(); - /// x - /// }), COption::Some("HEY".to_owned().as_mut_str())); - /// ``` - pub fn as_deref_mut(&mut self) -> COption<&mut T::Target> { - self.as_mut().map(|t| t.deref_mut()) - } -} - -impl COption> { - /// Transposes an `COption` of a [`Result`] into a [`Result`] of an `COption`. - /// - /// [`COption::None`] will be mapped to [`Ok`]`(`[`COption::None`]`)`. - /// [`COption::Some`]`(`[`Ok`]`(_))` and [`COption::Some`]`(`[`Err`]`(_))` will be mapped to - /// [`Ok`]`(`[`COption::Some`]`(_))` and [`Err`]`(_)`. - /// - /// [`COption::None`]: #variant.COption::None - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`COption::Some`]: #variant.COption::Some - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ```ignore - /// #[derive(Debug, Eq, PartialEq)] - /// struct COption::SomeErr; - /// - /// let x: Result, COption::SomeErr> = Ok(COption::Some(5)); - /// let y: COption> = COption::Some(Ok(5)); - /// assert_eq!(x, y.transpose()); - /// ``` - #[inline] - pub fn transpose(self) -> Result, E> { - match self { - COption::Some(Ok(x)) => Ok(COption::Some(x)), - COption::Some(Err(e)) => Err(e), - COption::None => Ok(COption::None), - } - } -} - -// This is a separate function to reduce the code size of .expect() itself. -#[inline(never)] -#[cold] -fn expect_failed(msg: &str) -> ! { - panic!("{}", msg) -} - -// // This is a separate function to reduce the code size of .expect_none() itself. -// #[inline(never)] -// #[cold] -// fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! { -// panic!("{}: {:?}", msg, value) -// } - -///////////////////////////////////////////////////////////////////////////// -// Trait implementations -///////////////////////////////////////////////////////////////////////////// - -impl Clone for COption { - #[inline] - fn clone(&self) -> Self { - match self { - COption::Some(x) => COption::Some(x.clone()), - COption::None => COption::None, - } - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - match (self, source) { - (COption::Some(to), COption::Some(from)) => to.clone_from(from), - (to, from) => *to = from.clone(), - } - } -} - -impl Default for COption { - /// Returns [`COption::None`][COption::COption::None]. - /// - /// # Examples - /// - /// ```ignore - /// let opt: COption = COption::default(); - /// assert!(opt.is_none()); - /// ``` - #[inline] - fn default() -> COption { - COption::None - } -} - -impl From for COption { - fn from(val: T) -> COption { - COption::Some(val) - } -} - -impl<'a, T> From<&'a COption> for COption<&'a T> { - fn from(o: &'a COption) -> COption<&'a T> { - o.as_ref() - } -} - -impl<'a, T> From<&'a mut COption> for COption<&'a mut T> { - fn from(o: &'a mut COption) -> COption<&'a mut T> { - o.as_mut() - } -} - -impl COption> { - /// Converts from `COption>` to `COption` - /// - /// # Examples - /// Basic usage: - /// ```ignore - /// #![feature(option_flattening)] - /// let x: COption> = COption::Some(COption::Some(6)); - /// assert_eq!(COption::Some(6), x.flatten()); - /// - /// let x: COption> = COption::Some(COption::None); - /// assert_eq!(COption::None, x.flatten()); - /// - /// let x: COption> = COption::None; - /// assert_eq!(COption::None, x.flatten()); - /// ``` - /// Flattening once only removes one level of nesting: - /// ```ignore - /// #![feature(option_flattening)] - /// let x: COption>> = COption::Some(COption::Some(COption::Some(6))); - /// assert_eq!(COption::Some(COption::Some(6)), x.flatten()); - /// assert_eq!(COption::Some(6), x.flatten().flatten()); - /// ``` - #[inline] - pub fn flatten(self) -> COption { - self.and_then(convert::identity) - } -} - -impl From> for COption { - fn from(option: Option) -> Self { - match option { - Some(value) => COption::Some(value), - None => COption::None, - } - } -} - -impl Into> for COption { - fn into(self) -> Option { - match self { - COption::Some(value) => Some(value), - COption::None => None, - } - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_from_rust_option() { - let option = Some(99u64); - let c_option: COption = option.into(); - assert_eq!(c_option, COption::Some(99u64)); - let expected = c_option.into(); - assert_eq!(option, expected); - - let option = None; - let c_option: COption = option.into(); - assert_eq!(c_option, COption::None); - let expected = c_option.into(); - assert_eq!(option, expected); - } -} diff --git a/program/src/pack.rs b/program/src/pack.rs deleted file mode 100644 index 7c0f355..0000000 --- a/program/src/pack.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! State transition types - -use solana_sdk::program_error::ProgramError; - -/// Check is a token state is initialized -pub trait IsInitialized { - /// Is initialized - fn is_initialized(&self) -> bool; -} - -/// Depends on Sized -pub trait Sealed: Sized {} - -/// Safely and efficiently (de)serialize account state -pub trait Pack: Sealed { - /// The length, in bytes, of the packed representation - const LEN: usize; - #[doc(hidden)] - fn pack_into_slice(&self, dst: &mut [u8]); - #[doc(hidden)] - fn unpack_from_slice(src: &[u8]) -> Result; - - /// Get the packed length - fn get_packed_len() -> usize { - Self::LEN - } - - /// Unpack from slice and check if initialized - fn unpack(input: &[u8]) -> Result - where - Self: IsInitialized, - { - let value = Self::unpack_unchecked(input)?; - if value.is_initialized() { - Ok(value) - } else { - Err(ProgramError::UninitializedAccount) - } - } - - /// Unpack from slice without checking if initialized - fn unpack_unchecked(input: &[u8]) -> Result { - if input.len() != Self::LEN { - return Err(ProgramError::InvalidAccountData); - } - Ok(Self::unpack_from_slice(input)?) - } - - /// Pack into slice - fn pack(src: Self, dst: &mut [u8]) -> Result<(), ProgramError> { - if dst.len() != Self::LEN { - return Err(ProgramError::InvalidAccountData); - } - src.pack_into_slice(dst); - Ok(()) - } -} diff --git a/program/src/processor.rs b/program/src/processor.rs index a4ce7a0..4ab5727 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -5,8 +5,6 @@ use crate::{ error::TokenError, instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, - option::COption, - pack::{IsInitialized, Pack}, state::{Account, AccountState, Mint, Multisig}, }; use num_traits::FromPrimitive; @@ -16,6 +14,8 @@ use solana_sdk::{ entrypoint::ProgramResult, info, program_error::{PrintProgramError, ProgramError}, + program_option::COption, + program_pack::{IsInitialized, Pack}, pubkey::Pubkey, sysvar::{rent::Rent, Sysvar}, }; diff --git a/program/src/state.rs b/program/src/state.rs index 5d14af7..3622471 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -1,15 +1,14 @@ //! State transition types -use crate::{ - instruction::MAX_SIGNERS, - option::COption, - pack::{IsInitialized, Pack, Sealed}, -}; +use crate::instruction::MAX_SIGNERS; use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; use num_enum::TryFromPrimitive; -use solana_sdk::{program_error::ProgramError, pubkey::Pubkey}; - -impl Sealed for Option {} +use solana_sdk::{ + program_error::ProgramError, + program_option::COption, + program_pack::{IsInitialized, Pack, Sealed}, + pubkey::Pubkey, +}; /// Mint data. #[repr(C)] From 364573768639566c6e5e50be947ffef000eec2b3 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 13:14:13 -0700 Subject: [PATCH 077/335] cargo fmt --- program/src/processor.rs | 874 +++++++++++++++++++-------------------- 1 file changed, 437 insertions(+), 437 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 4ab5727..dcc7c7d 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -36,22 +36,22 @@ impl Processor { let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow())?; - if mint.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } + if mint.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } - if !rent.is_exempt(mint_info.lamports(), mint_data_len) { - return Err(TokenError::NotRentExempt.into()); - } + if !rent.is_exempt(mint_info.lamports(), mint_data_len) { + return Err(TokenError::NotRentExempt.into()); + } - mint.mint_authority = COption::Some(mint_authority); - mint.decimals = decimals; - mint.is_initialized = true; - mint.freeze_authority = freeze_authority; + mint.mint_authority = COption::Some(mint_authority); + mint.decimals = decimals; + mint.is_initialized = true; + mint.freeze_authority = freeze_authority; Mint::pack(mint, &mut mint_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. @@ -64,39 +64,39 @@ impl Processor { let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; let mut account = Account::unpack_unchecked(&new_account_info.data.borrow())?; - if account.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } + if account.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } - if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } + if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) { + return Err(TokenError::NotRentExempt.into()); + } - if *mint_info.key != crate::native_mint::id() { - let _ = Mint::unpack(&mint_info.data.borrow_mut()) - .map_err(|_| Into::::into(TokenError::InvalidMint))?; - } + if *mint_info.key != crate::native_mint::id() { + let _ = Mint::unpack(&mint_info.data.borrow_mut()) + .map_err(|_| Into::::into(TokenError::InvalidMint))?; + } - account.mint = *mint_info.key; - account.owner = *owner_info.key; - account.delegate = COption::None; - account.delegated_amount = 0; - account.state = AccountState::Initialized; - if *mint_info.key == crate::native_mint::id() { - let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); - account.is_native = COption::Some(rent_exempt_reserve); - account.amount = new_account_info - .lamports() - .checked_sub(rent_exempt_reserve) - .ok_or(TokenError::Overflow)?; - } else { - account.is_native = COption::None; - account.amount = 0; - }; + account.mint = *mint_info.key; + account.owner = *owner_info.key; + account.delegate = COption::None; + account.delegated_amount = 0; + account.state = AccountState::Initialized; + if *mint_info.key == crate::native_mint::id() { + let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); + account.is_native = COption::Some(rent_exempt_reserve); + account.amount = new_account_info + .lamports() + .checked_sub(rent_exempt_reserve) + .ok_or(TokenError::Overflow)?; + } else { + account.is_native = COption::None; + account.amount = 0; + }; Account::pack(account, &mut new_account_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. @@ -107,31 +107,31 @@ impl Processor { let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; let mut multisig = Multisig::unpack_unchecked(&multisig_info.data.borrow())?; - if multisig.is_initialized { - return Err(TokenError::AlreadyInUse.into()); - } + if multisig.is_initialized { + return Err(TokenError::AlreadyInUse.into()); + } - if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) { - return Err(TokenError::NotRentExempt.into()); - } + if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) { + return Err(TokenError::NotRentExempt.into()); + } - let signer_infos = account_info_iter.as_slice(); - multisig.m = m; - multisig.n = signer_infos.len() as u8; - if !is_valid_signer_index(multisig.n as usize) { - return Err(TokenError::InvalidNumberOfProvidedSigners.into()); - } - if !is_valid_signer_index(multisig.m as usize) { - return Err(TokenError::InvalidNumberOfRequiredSigners.into()); - } - for (i, signer_info) in signer_infos.iter().enumerate() { - multisig.signers[i] = *signer_info.key; - } - multisig.is_initialized = true; + let signer_infos = account_info_iter.as_slice(); + multisig.m = m; + multisig.n = signer_infos.len() as u8; + if !is_valid_signer_index(multisig.n as usize) { + return Err(TokenError::InvalidNumberOfProvidedSigners.into()); + } + if !is_valid_signer_index(multisig.m as usize) { + return Err(TokenError::InvalidNumberOfRequiredSigners.into()); + } + for (i, signer_info) in signer_infos.iter().enumerate() { + multisig.signers[i] = *signer_info.key; + } + multisig.is_initialized = true; Multisig::pack(multisig, &mut multisig_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes a [Transfer](enum.TokenInstruction.html) instruction. @@ -161,79 +161,79 @@ impl Processor { let mut source_account = Account::unpack(&source_account_info.data.borrow())?; let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if source_account.is_frozen() || dest_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + if source_account.is_frozen() || dest_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } if source_account.mint != dest_account.mint { return Err(TokenError::MintMismatch.into()); } - if let Some((mint_info, expected_decimals)) = expected_mint_info { - if source_account.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } - - let mint = Mint::unpack(&mint_info.data.borrow_mut())?; - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } + if let Some((mint_info, expected_decimals)) = expected_mint_info { + if source_account.mint != *mint_info.key { + return Err(TokenError::MintMismatch.into()); + } - match source_account.delegate { - COption::Some(ref delegate) if authority_info.key == delegate => { - Self::validate_owner( - program_id, - delegate, - authority_info, - account_info_iter.as_slice(), - )?; - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - source_account.delegated_amount = source_account - .delegated_amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } - } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, - }; + let mint = Mint::unpack(&mint_info.data.borrow_mut())?; + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } - source_account.amount = source_account - .amount + match source_account.delegate { + COption::Some(ref delegate) if authority_info.key == delegate => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount = source_account + .delegated_amount .checked_sub(amount) .ok_or(TokenError::Overflow)?; - dest_account.amount = dest_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?, + }; - if source_account.is_native() { - let source_starting_lamports = source_account_info.lamports(); - **source_account_info.lamports.borrow_mut() = source_starting_lamports - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; + source_account.amount = source_account + .amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + + if source_account.is_native() { + let source_starting_lamports = source_account_info.lamports(); + **source_account_info.lamports.borrow_mut() = source_starting_lamports + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; - let dest_starting_lamports = dest_account_info.lamports(); - **dest_account_info.lamports.borrow_mut() = dest_starting_lamports - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - } + let dest_starting_lamports = dest_account_info.lamports(); + **dest_account_info.lamports.borrow_mut() = dest_starting_lamports + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + } Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes an [Approve](enum.TokenInstruction.html) instruction. @@ -256,34 +256,34 @@ impl Processor { let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - if let Some((mint_info, expected_decimals)) = expected_mint_info { - if source_account.mint != *mint_info.key { - return Err(TokenError::MintMismatch.into()); - } + if let Some((mint_info, expected_decimals)) = expected_mint_info { + if source_account.mint != *mint_info.key { + return Err(TokenError::MintMismatch.into()); + } - let mint = Mint::unpack(&mint_info.data.borrow_mut())?; - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } + let mint = Mint::unpack(&mint_info.data.borrow_mut())?; + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); } + } - Self::validate_owner( - program_id, - &source_account.owner, - owner_info, - account_info_iter.as_slice(), - )?; + Self::validate_owner( + program_id, + &source_account.owner, + owner_info, + account_info_iter.as_slice(), + )?; - source_account.delegate = COption::Some(*delegate_info.key); - source_account.delegated_amount = amount; + source_account.delegate = COption::Some(*delegate_info.key); + source_account.delegated_amount = amount; Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes an [Revoke](enum.TokenInstruction.html) instruction. @@ -293,25 +293,25 @@ impl Processor { let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - let owner_info = next_account_info(account_info_iter)?; + let owner_info = next_account_info(account_info_iter)?; - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - Self::validate_owner( - program_id, - &source_account.owner, - owner_info, - account_info_iter.as_slice(), - )?; + Self::validate_owner( + program_id, + &source_account.owner, + owner_info, + account_info_iter.as_slice(), + )?; - source_account.delegate = COption::None; - source_account.delegated_amount = 0; + source_account.delegate = COption::None; + source_account.delegated_amount = 0; Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes a [SetAuthority](enum.TokenInstruction.html) instruction. @@ -328,75 +328,75 @@ impl Processor { if account_info.data_len() == Account::get_packed_len() { let mut account = Account::unpack(&account_info.data.borrow())?; - if account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + if account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - match authority_type { - AuthorityType::AccountOwner => { - Self::validate_owner( - program_id, - &account.owner, - authority_info, - account_info_iter.as_slice(), - )?; - - if let COption::Some(authority) = new_authority { - account.owner = authority; - } else { - return Err(TokenError::InvalidInstruction.into()); - } - } - AuthorityType::CloseAccount => { - let authority = account.close_authority.unwrap_or(account.owner); - Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - )?; - account.close_authority = new_authority; - } - _ => { - return Err(TokenError::AuthorityTypeNotSupported.into()); + match authority_type { + AuthorityType::AccountOwner => { + Self::validate_owner( + program_id, + &account.owner, + authority_info, + account_info_iter.as_slice(), + )?; + + if let COption::Some(authority) = new_authority { + account.owner = authority; + } else { + return Err(TokenError::InvalidInstruction.into()); } } + AuthorityType::CloseAccount => { + let authority = account.close_authority.unwrap_or(account.owner); + Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + )?; + account.close_authority = new_authority; + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); + } + } Account::pack(account, &mut account_info.data.borrow_mut())?; } else if account_info.data_len() == Mint::get_packed_len() { let mut mint = Mint::unpack(&account_info.data.borrow())?; - match authority_type { - AuthorityType::MintTokens => { - // Once a mint's supply is fixed, it cannot be undone by setting a new - // mint_authority - let mint_authority = mint - .mint_authority - .ok_or(Into::::into(TokenError::FixedSupply))?; - Self::validate_owner( - program_id, - &mint_authority, - authority_info, - account_info_iter.as_slice(), - )?; - mint.mint_authority = new_authority; - } - AuthorityType::FreezeAccount => { - // Once a mint's freeze authority is disabled, it cannot be re-enabled by - // setting a new freeze_authority - let freeze_authority = mint - .freeze_authority - .ok_or(Into::::into(TokenError::MintCannotFreeze))?; - Self::validate_owner( - program_id, - &freeze_authority, - authority_info, - account_info_iter.as_slice(), - )?; - mint.freeze_authority = new_authority; - } - _ => { - return Err(TokenError::AuthorityTypeNotSupported.into()); - } + match authority_type { + AuthorityType::MintTokens => { + // Once a mint's supply is fixed, it cannot be undone by setting a new + // mint_authority + let mint_authority = mint + .mint_authority + .ok_or(Into::::into(TokenError::FixedSupply))?; + Self::validate_owner( + program_id, + &mint_authority, + authority_info, + account_info_iter.as_slice(), + )?; + mint.mint_authority = new_authority; + } + AuthorityType::FreezeAccount => { + // Once a mint's freeze authority is disabled, it cannot be re-enabled by + // setting a new freeze_authority + let freeze_authority = mint + .freeze_authority + .ok_or(Into::::into(TokenError::MintCannotFreeze))?; + Self::validate_owner( + program_id, + &freeze_authority, + authority_info, + account_info_iter.as_slice(), + )?; + mint.freeze_authority = new_authority; + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); } + } Mint::pack(mint, &mut account_info.data.borrow_mut())?; } else { return Err(ProgramError::InvalidArgument); @@ -418,48 +418,48 @@ impl Processor { let owner_info = next_account_info(account_info_iter)?; let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; - if dest_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + if dest_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - if dest_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if mint_info.key != &dest_account.mint { - return Err(TokenError::MintMismatch.into()); - } + if dest_account.is_native() { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key != &dest_account.mint { + return Err(TokenError::MintMismatch.into()); + } let mut mint = Mint::unpack(&mint_info.data.borrow())?; - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } - match mint.mint_authority { - COption::Some(mint_authority) => Self::validate_owner( - program_id, - &mint_authority, - owner_info, - account_info_iter.as_slice(), - )?, - COption::None => return Err(TokenError::FixedSupply.into()), - } + match mint.mint_authority { + COption::Some(mint_authority) => Self::validate_owner( + program_id, + &mint_authority, + owner_info, + account_info_iter.as_slice(), + )?, + COption::None => return Err(TokenError::FixedSupply.into()), + } - dest_account.amount = dest_account - .amount - .checked_add(amount) - .ok_or(TokenError::Overflow)?; + dest_account.amount = dest_account + .amount + .checked_add(amount) + .ok_or(TokenError::Overflow)?; - mint.supply = mint - .supply - .checked_add(amount) - .ok_or(TokenError::Overflow)?; + mint.supply = mint + .supply + .checked_add(amount) + .ok_or(TokenError::Overflow)?; Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?; Mint::pack(mint, &mut mint_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes a [Burn](enum.TokenInstruction.html) instruction. @@ -478,66 +478,66 @@ impl Processor { let mut source_account = Account::unpack(&source_account_info.data.borrow())?; let mut mint = Mint::unpack(&mint_info.data.borrow())?; - if source_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if mint_info.key != &source_account.mint { - return Err(TokenError::MintMismatch.into()); - } - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + if source_account.is_native() { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } - match source_account.delegate { - COption::Some(ref delegate) if authority_info.key == delegate => { - Self::validate_owner( - program_id, - delegate, - authority_info, - account_info_iter.as_slice(), - )?; - - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - source_account.delegated_amount = source_account - .delegated_amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } - } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, - } + match source_account.delegate { + COption::Some(ref delegate) if authority_info.key == delegate => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; - source_account.amount = source_account - .amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - mint.supply = mint - .supply + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount = source_account + .delegated_amount .checked_sub(amount) .ok_or(TokenError::Overflow)?; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( + program_id, + &source_account.owner, + authority_info, + account_info_iter.as_slice(), + )?, + } + + source_account.amount = source_account + .amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + mint.supply = mint + .supply + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; Mint::pack(mint, &mut mint_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. @@ -548,31 +548,31 @@ impl Processor { let authority_info = next_account_info(account_info_iter)?; let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - if !source_account.is_native() && source_account.amount != 0 { - return Err(TokenError::NonNativeHasBalance.into()); - } + if !source_account.is_native() && source_account.amount != 0 { + return Err(TokenError::NonNativeHasBalance.into()); + } - let authority = source_account - .close_authority - .unwrap_or(source_account.owner); - Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - )?; + let authority = source_account + .close_authority + .unwrap_or(source_account.owner); + Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + )?; - let dest_starting_lamports = dest_account_info.lamports(); - **dest_account_info.lamports.borrow_mut() = dest_starting_lamports - .checked_add(source_account_info.lamports()) - .ok_or(TokenError::Overflow)?; + let dest_starting_lamports = dest_account_info.lamports(); + **dest_account_info.lamports.borrow_mut() = dest_starting_lamports + .checked_add(source_account_info.lamports()) + .ok_or(TokenError::Overflow)?; - **source_account_info.lamports.borrow_mut() = 0; - source_account.amount = 0; + **source_account_info.lamports.borrow_mut() = 0; + source_account.amount = 0; Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes a [FreezeAccount](enum.TokenInstruction.html) or a @@ -588,36 +588,36 @@ impl Processor { let authority_info = next_account_info(account_info_iter)?; let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - if source_account.is_native() { - return Err(TokenError::NativeNotSupported.into()); - } - if mint_info.key != &source_account.mint { - return Err(TokenError::MintMismatch.into()); - } - if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { - return Err(TokenError::InvalidState.into()); - } + if source_account.is_native() { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { + return Err(TokenError::InvalidState.into()); + } - let mint = Mint::unpack(&mint_info.data.borrow_mut())?; - match mint.freeze_authority { - COption::Some(authority) => Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - ), - COption::None => Err(TokenError::MintCannotFreeze.into()), - }?; + let mint = Mint::unpack(&mint_info.data.borrow_mut())?; + match mint.freeze_authority { + COption::Some(authority) => Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + ), + COption::None => Err(TokenError::MintCannotFreeze.into()), + }?; - source_account.state = if freeze { - AccountState::Frozen - } else { - AccountState::Initialized - }; + source_account.state = if freeze { + AccountState::Frozen + } else { + AccountState::Initialized + }; Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - Ok(()) + Ok(()) } /// Processes an [Instruction](enum.Instruction.html). @@ -713,9 +713,9 @@ impl Processor { && owner_account_info.data_len() == Multisig::get_packed_len() { let multisig = Multisig::unpack(&owner_account_info.data.borrow())?; - let mut num_signers = 0; + let mut num_signers = 0; let mut matched = [false; MAX_SIGNERS]; - for signer in signers.iter() { + for signer in signers.iter() { for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() { if key == signer.key && !matched[position] { if !signer.is_signer { @@ -726,9 +726,9 @@ impl Processor { } } } - if num_signers < multisig.m { - return Err(ProgramError::MissingRequiredSignature); - } + if num_signers < multisig.m { + return Err(ProgramError::MissingRequiredSignature); + } return Ok(()); } else if !owner_account_info.is_signer { return Err(ProgramError::MissingRequiredSignature); @@ -1010,7 +1010,7 @@ mod tests { ) .unwrap(); let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); - assert_eq!(mint.freeze_authority, COption::Some(owner_key)); + assert_eq!(mint.freeze_authority, COption::Some(owner_key)); } #[test] @@ -1219,10 +1219,10 @@ mod tests { // source-delegate transfer let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.amount = 1000; - account.delegated_amount = 1000; - account.delegate = COption::Some(account1_key); - account.owner = owner_key; + account.amount = 1000; + account.delegated_amount = 1000; + account.delegate = COption::Some(account1_key); + account.owner = owner_key; Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( @@ -1490,7 +1490,7 @@ mod tests { ) .unwrap(); let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; + account.mint = mint2_key; Account::pack(account, &mut mismatch_account.data).unwrap(); // mint to account @@ -1718,7 +1718,7 @@ mod tests { .unwrap() } let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000); + assert_eq!(account.amount, 1000); // insufficient funds assert_eq!( @@ -1876,16 +1876,16 @@ mod tests { ) .unwrap(); let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!( + assert_eq!( mint, - Mint { - mint_authority: COption::Some(owner_key), - supply: 0, - decimals, - is_initialized: true, - freeze_authority: COption::None, - } - ); + Mint { + mint_authority: COption::Some(owner_key), + supply: 0, + decimals, + is_initialized: true, + freeze_authority: COption::None, + } + ); // create account do_process_instruction( @@ -1907,7 +1907,7 @@ mod tests { .unwrap(); let _ = Mint::unpack(&mut mint_account.data).unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); + assert_eq!(account.amount, 42); // mint to 2, with incorrect decimals assert_eq!( @@ -1929,7 +1929,7 @@ mod tests { let _ = Mint::unpack(&mut mint_account.data).unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); + assert_eq!(account.amount, 42); // mint to 2 do_process_instruction( @@ -1948,7 +1948,7 @@ mod tests { .unwrap(); let _ = Mint::unpack(&mut mint_account.data).unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 84); + assert_eq!(account.amount, 84); } #[test] @@ -2452,7 +2452,7 @@ mod tests { // set close_authority when currently self let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(account1_key); + account.close_authority = COption::Some(account1_key); Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( @@ -2865,7 +2865,7 @@ mod tests { // mint_to when mint_authority is account owner let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap(); - mint.mint_authority = COption::Some(account1_key); + mint.mint_authority = COption::Some(account1_key); Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( mint_to( @@ -3003,7 +3003,7 @@ mod tests { ) .unwrap(); let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; + account.mint = mint2_key; Account::pack(account, &mut mismatch_account.data).unwrap(); // mint to @@ -3014,9 +3014,9 @@ mod tests { .unwrap(); let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 42); + assert_eq!(mint.supply, 42); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); + assert_eq!(account.amount, 42); // mint to another account to test supply accumulation do_process_instruction( @@ -3026,9 +3026,9 @@ mod tests { .unwrap(); let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 84); + assert_eq!(mint.supply, 84); let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert_eq!(account.amount, 42); + assert_eq!(account.amount, 42); // missing signer let mut instruction = @@ -3201,7 +3201,7 @@ mod tests { ) .unwrap(); let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.owner = mint_key; + account.owner = mint_key; Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), @@ -3232,9 +3232,9 @@ mod tests { ) .unwrap(); let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.delegated_amount = 1000; - account.delegate = COption::Some(account1_key); - account.owner = owner_key; + account.delegated_amount = 1000; + account.delegate = COption::Some(account1_key); + account.owner = owner_key; Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( burn( @@ -3281,9 +3281,9 @@ mod tests { ) .unwrap(); let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.delegated_amount = 1000; - account.delegate = COption::Some(mint_key); - account.owner = owner_key; + account.delegated_amount = 1000; + account.delegate = COption::Some(mint_key); + account.owner = owner_key; Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), @@ -3402,7 +3402,7 @@ mod tests { ) .unwrap(); let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; + account.mint = mint2_key; Account::pack(account, &mut mismatch_account.data).unwrap(); // mint to account @@ -3470,9 +3470,9 @@ mod tests { .unwrap(); let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 1000 - 42); + assert_eq!(mint.supply, 1000 - 42); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42); + assert_eq!(account.amount, 1000 - 42); // insufficient funds assert_eq!( @@ -3540,9 +3540,9 @@ mod tests { // match let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 1000 - 42 - 84); + assert_eq!(mint.supply, 1000 - 42 - 84); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42 - 84); + assert_eq!(account.amount, 1000 - 42 - 84); // insufficient funds approved via delegate assert_eq!( @@ -3999,10 +3999,10 @@ mod tests { let mut lamports = 0; let mut data = vec![0; Multisig::get_packed_len()]; let mut multisig = Multisig::unpack_unchecked(&data).unwrap(); - multisig.m = MAX_SIGNERS as u8; - multisig.n = MAX_SIGNERS as u8; - multisig.signers = signer_keys; - multisig.is_initialized = true; + multisig.m = MAX_SIGNERS as u8; + multisig.n = MAX_SIGNERS as u8; + multisig.signers = signer_keys; + multisig.is_initialized = true; Multisig::pack(multisig, &mut data).unwrap(); let owner_account_info = AccountInfo::new( &owner_key, @@ -4022,7 +4022,7 @@ mod tests { { let mut multisig = Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 1; + multisig.m = 1; Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); @@ -4031,8 +4031,8 @@ mod tests { { let mut multisig = Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 1; + multisig.m = 2; + multisig.n = 1; Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } assert_eq!( @@ -4044,8 +4044,8 @@ mod tests { { let mut multisig = Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 0; - multisig.n = 11; + multisig.m = 0; + multisig.n = 11; Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap(); @@ -4054,8 +4054,8 @@ mod tests { { let mut multisig = Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; + multisig.m = 2; + multisig.n = 11; Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } assert_eq!( @@ -4066,8 +4066,8 @@ mod tests { { let mut multisig = Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; + multisig.m = 2; + multisig.n = 11; Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } assert_eq!( @@ -4079,8 +4079,8 @@ mod tests { { let mut multisig = Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); - multisig.m = 2; - multisig.n = 11; + multisig.m = 2; + multisig.n = 11; Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[5..7]) @@ -4091,7 +4091,7 @@ mod tests { let mut multisig = Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap(); multisig.m = 11; - multisig.n = 11; + multisig.n = 11; Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap(); } signers[5].is_signer = false; @@ -4195,8 +4195,8 @@ mod tests { // source-close-authority close let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(account1_key); - account.owner = owner_key; + account.close_authority = COption::Some(account1_key); + account.owner = owner_key; Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( close_account( @@ -4286,7 +4286,7 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); + assert_eq!(account.amount, 42); // initialize native account do_process_instruction( @@ -4306,8 +4306,8 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 42); + assert!(account.is_native()); + assert_eq!(account.amount, 42); // close non-native account with balance assert_eq!( @@ -4356,7 +4356,7 @@ mod tests { assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); + assert_eq!(account.amount, 0); // fund and initialize new non-native account to test close authority let account_key = pubkey_rand(); @@ -4423,7 +4423,7 @@ mod tests { assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); + assert_eq!(account.amount, 0); // close native account do_process_instruction( @@ -4436,13 +4436,13 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account_account.lamports, 0); - assert_eq!(account.amount, 0); - assert_eq!( - account3_account.lamports, - 3 * account_minimum_balance() + 2 + 42 - ); + assert!(account.is_native()); + assert_eq!(account_account.lamports, 0); + assert_eq!(account.amount, 0); + assert_eq!( + account3_account.lamports, + 3 * account_minimum_balance() + 2 + 42 + ); } #[test] @@ -4486,8 +4486,8 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); + assert!(account.is_native()); + assert_eq!(account.amount, 40); // initialize native account do_process_instruction( @@ -4507,8 +4507,8 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); + assert!(account.is_native()); + assert_eq!(account.amount, 0); // mint_to unsupported assert_eq!( @@ -4598,12 +4598,12 @@ mod tests { .unwrap(); assert_eq!(account_account.lamports, account_minimum_balance()); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); + assert!(account.is_native()); + assert_eq!(account.amount, 0); assert_eq!(account2_account.lamports, account_minimum_balance() + 40); let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); + assert!(account.is_native()); + assert_eq!(account.amount, 40); // close native account do_process_instruction( @@ -4618,8 +4618,8 @@ mod tests { assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); + assert!(account.is_native()); + assert_eq!(account.amount, 0); } #[test] @@ -4698,7 +4698,7 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); + assert_eq!(account.amount, u64::MAX); // attempt to mint one more to account assert_eq!( @@ -4721,7 +4721,7 @@ mod tests { ) ); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); + assert_eq!(account.amount, u64::MAX); // atttempt to mint one more to the other account assert_eq!( @@ -4751,7 +4751,7 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX - 100); + assert_eq!(account.amount, u64::MAX - 100); do_process_instruction( mint_to( @@ -4771,11 +4771,11 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); + assert_eq!(account.amount, u64::MAX); // manipulate account balance to attempt overflow transfer let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.amount = 1; + account.amount = 1; Account::pack(account, &mut account2_account.data).unwrap(); assert_eq!( @@ -4861,7 +4861,7 @@ mod tests { // no transfer if either account is frozen let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.state = AccountState::Frozen; + account.state = AccountState::Frozen; Account::pack(account, &mut account2_account.data).unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), @@ -4884,10 +4884,10 @@ mod tests { ); let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.state = AccountState::Initialized; + account.state = AccountState::Initialized; Account::pack(account, &mut account_account.data).unwrap(); let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.state = AccountState::Frozen; + account.state = AccountState::Frozen; Account::pack(account, &mut account2_account.data).unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), @@ -4911,7 +4911,7 @@ mod tests { // no approve if account is frozen let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.state = AccountState::Frozen; + account.state = AccountState::Frozen; Account::pack(account, &mut account_account.data).unwrap(); let delegate_key = pubkey_rand(); let mut delegate_account = SolanaAccount::default(); @@ -4937,8 +4937,8 @@ mod tests { // no revoke if account is frozen let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.delegate = COption::Some(delegate_key); - account.delegated_amount = 100; + account.delegate = COption::Some(delegate_key); + account.delegated_amount = 100; Account::pack(account, &mut account_account.data).unwrap(); assert_eq!( Err(TokenError::AccountFrozen.into()), @@ -5036,7 +5036,7 @@ mod tests { // thaw where mint freeze_authority is account let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.state = AccountState::Frozen; + account.state = AccountState::Frozen; Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), @@ -5106,7 +5106,7 @@ mod tests { // missing freeze_authority let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - mint.freeze_authority = COption::Some(owner_key); + mint.freeze_authority = COption::Some(owner_key); Mint::pack(mint, &mut mint_account.data).unwrap(); assert_eq!( Err(TokenError::OwnerMismatch.into()), @@ -5132,7 +5132,7 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Frozen); + assert_eq!(account.state, AccountState::Frozen); // check explicit freeze assert_eq!( @@ -5159,6 +5159,6 @@ mod tests { ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Initialized); + assert_eq!(account.state, AccountState::Initialized); } } From 79d78c93f68486ecf8869d5ab2ff04f0f3f6310f Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 21 Sep 2020 14:49:34 -0700 Subject: [PATCH 078/335] retain v2 error values --- program/src/error.rs | 3 +++ program/src/processor.rs | 1 + 2 files changed, 4 insertions(+) diff --git a/program/src/error.rs b/program/src/error.rs index e56fde6..32cd9d2 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -34,6 +34,9 @@ pub enum TokenError { /// Invalid number of required signers. #[error("Invalid number of required signers")] InvalidNumberOfRequiredSigners, + /// State is uninitialized. + #[error("State is unititialized")] + UninitializedState, /// Instruction does not support native tokens #[error("Instruction does not support native tokens")] NativeNotSupported, diff --git a/program/src/processor.rs b/program/src/processor.rs index dcc7c7d..baa1e33 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -758,6 +758,7 @@ impl PrintProgramError for TokenError { TokenError::InvalidNumberOfRequiredSigners => { info!("Error: Invalid number of required signers") } + TokenError::UninitializedState => info!("Error: State is uninitialized"), TokenError::NativeNotSupported => { info!("Error: Instruction does not support native tokens") } From a2ca5af8786b0e22bd7305b2415b950afa9eb85a Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 21 Sep 2020 20:28:24 -0600 Subject: [PATCH 079/335] Standardize failure case ordering (#509) * Standardize processor failure-case ordering * Fix token-swap test --- program/src/processor.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index baa1e33..7c32213 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -161,12 +161,12 @@ impl Processor { let mut source_account = Account::unpack(&source_account_info.data.borrow())?; let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; - if source_account.amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } if source_account.is_frozen() || dest_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } + if source_account.amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } if source_account.mint != dest_account.mint { return Err(TokenError::MintMismatch.into()); } @@ -478,17 +478,17 @@ impl Processor { let mut source_account = Account::unpack(&source_account_info.data.borrow())?; let mut mint = Mint::unpack(&mint_info.data.borrow())?; + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } - if mint_info.key != &source_account.mint { - return Err(TokenError::MintMismatch.into()); - } if source_account.amount < amount { return Err(TokenError::InsufficientFunds.into()); } - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); + if mint_info.key != &source_account.mint { + return Err(TokenError::MintMismatch.into()); } if let Some(expected_decimals) = expected_decimals { @@ -588,15 +588,15 @@ impl Processor { let authority_info = next_account_info(account_info_iter)?; let mut source_account = Account::unpack(&source_account_info.data.borrow())?; + if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { + return Err(TokenError::InvalidState.into()); + } if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } if mint_info.key != &source_account.mint { return Err(TokenError::MintMismatch.into()); } - if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { - return Err(TokenError::InvalidState.into()); - } let mint = Mint::unpack(&mint_info.data.borrow_mut())?; match mint.freeze_authority { @@ -3402,9 +3402,6 @@ mod tests { ], ) .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); // mint to account do_process_instruction( @@ -3413,6 +3410,16 @@ mod tests { ) .unwrap(); + // mint to mismatch account and change mint key + do_process_instruction( + mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); + account.mint = mint2_key; + Account::pack(account, &mut mismatch_account.data).unwrap(); + // missing signer let mut instruction = burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap(); @@ -3471,7 +3478,7 @@ mod tests { .unwrap(); let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 1000 - 42); + assert_eq!(mint.supply, 2000 - 42); let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 1000 - 42); @@ -3541,7 +3548,7 @@ mod tests { // match let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 1000 - 42 - 84); + assert_eq!(mint.supply, 2000 - 42 - 84); let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 1000 - 42 - 84); From ab591241879f6c70136d379739d7c01d7d5eebb2 Mon Sep 17 00:00:00 2001 From: Jack May Date: Tue, 22 Sep 2020 00:55:59 -0700 Subject: [PATCH 080/335] Rename x2 instructions to xChecked --- program/src/instruction.rs | 66 ++++++++++++++--------------- program/src/processor.rs | 86 +++++++++++++++++++------------------- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index ae01523..de75b73 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -233,7 +233,7 @@ pub enum TokenInstruction { /// transferred to the destination account. /// /// This instruction differs from Transfer in that the token mint and decimals value is - /// asserted by the caller. This may be useful when creating transactions offline or within a + /// checked by the caller. This may be useful when creating transactions offline or within a /// hardware wallet. /// /// Accounts expected by this instruction: @@ -250,7 +250,7 @@ pub enum TokenInstruction { /// 2. `[writable]` The destination account. /// 3. `[]` The source account's multisignature owner/delegate. /// 4. ..4+M `[signer]` M signer accounts. - Transfer2 { + TransferChecked { /// The amount of tokens to transfer. amount: u64, /// Expected number of base 10 digits to the right of the decimal place. @@ -259,7 +259,7 @@ pub enum TokenInstruction { /// Approves a delegate. A delegate is given the authority over /// tokens on behalf of the source account's owner. /// - /// This instruction differs from Approve in that the token mint and decimals value is asserted + /// This instruction differs from Approve in that the token mint and decimals value is checked /// by the caller. This may be useful when creating transactions offline or within a hardware /// wallet. /// @@ -277,7 +277,7 @@ pub enum TokenInstruction { /// 2. `[]` The delegate. /// 3. `[]` The source account's multisignature owner. /// 4. ..4+M `[signer]` M signer accounts - Approve2 { + ApproveChecked { /// The amount of tokens the delegate is approved for. amount: u64, /// Expected number of base 10 digits to the right of the decimal place. @@ -285,7 +285,7 @@ pub enum TokenInstruction { }, /// Mints new tokens to an account. The native mint does not support minting. /// - /// This instruction differs from MintTo in that the decimals value is asserted by the + /// This instruction differs from MintTo in that the decimals value is checked by the /// caller. This may be useful when creating transactions offline or within a hardware wallet. /// /// Accounts expected by this instruction: @@ -300,16 +300,16 @@ pub enum TokenInstruction { /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. /// 3. ..3+M `[signer]` M signer accounts. - MintTo2 { + MintToChecked { /// The amount of new tokens to mint. amount: u64, /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, - /// Burns tokens by removing them from an account. `Burn2` does not support accounts + /// Burns tokens by removing them from an account. `BurnChecked` does not support accounts /// associated with the native mint, use `CloseAccount` instead. /// - /// This instruction differs from Burn in that the decimals value is asserted by the caller. + /// This instruction differs from Burn in that the decimals value is checked by the caller. /// This may be useful when creating transactions offline or within a hardware wallet. /// /// Accounts expected by this instruction: @@ -324,7 +324,7 @@ pub enum TokenInstruction { /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. /// 3. ..3+M `[signer]` M signer accounts. - Burn2 { + BurnChecked { /// The amount of tokens to burn. amount: u64, /// Expected number of base 10 digits to the right of the decimal place. @@ -392,7 +392,7 @@ impl TokenInstruction { .ok_or(InvalidInstruction)?; let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - Self::Transfer2 { amount, decimals } + Self::TransferChecked { amount, decimals } } 13 => { let (amount, rest) = rest.split_at(8); @@ -403,7 +403,7 @@ impl TokenInstruction { .ok_or(InvalidInstruction)?; let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - Self::Approve2 { amount, decimals } + Self::ApproveChecked { amount, decimals } } 14 => { let (amount, rest) = rest.split_at(8); @@ -414,7 +414,7 @@ impl TokenInstruction { .ok_or(InvalidInstruction)?; let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - Self::MintTo2 { amount, decimals } + Self::MintToChecked { amount, decimals } } 15 => { let (amount, rest) = rest.split_at(8); @@ -425,7 +425,7 @@ impl TokenInstruction { .ok_or(InvalidInstruction)?; let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - Self::Burn2 { amount, decimals } + Self::BurnChecked { amount, decimals } } _ => return Err(TokenError::InvalidInstruction.into()), @@ -479,22 +479,22 @@ impl TokenInstruction { Self::CloseAccount => buf.push(9), Self::FreezeAccount => buf.push(10), Self::ThawAccount => buf.push(11), - &Self::Transfer2 { amount, decimals } => { + &Self::TransferChecked { amount, decimals } => { buf.push(12); buf.extend_from_slice(&amount.to_le_bytes()); buf.push(decimals); } - &Self::Approve2 { amount, decimals } => { + &Self::ApproveChecked { amount, decimals } => { buf.push(13); buf.extend_from_slice(&amount.to_le_bytes()); buf.push(decimals); } - &Self::MintTo2 { amount, decimals } => { + &Self::MintToChecked { amount, decimals } => { buf.push(14); buf.extend_from_slice(&amount.to_le_bytes()); buf.push(decimals); } - &Self::Burn2 { amount, decimals } => { + &Self::BurnChecked { amount, decimals } => { buf.push(15); buf.extend_from_slice(&amount.to_le_bytes()); buf.push(decimals); @@ -910,9 +910,9 @@ pub fn thaw_account( }) } -/// Creates a `Transfer2` instruction. +/// Creates a `TransferChecked` instruction. #[allow(clippy::too_many_arguments)] -pub fn transfer2( +pub fn transfer_checked( token_program_id: &Pubkey, source_pubkey: &Pubkey, mint_pubkey: &Pubkey, @@ -922,7 +922,7 @@ pub fn transfer2( amount: u64, decimals: u8, ) -> Result { - let data = TokenInstruction::Transfer2 { amount, decimals }.pack(); + let data = TokenInstruction::TransferChecked { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*source_pubkey, false)); @@ -943,9 +943,9 @@ pub fn transfer2( }) } -/// Creates an `Approve2` instruction. +/// Creates an `ApproveChecked` instruction. #[allow(clippy::too_many_arguments)] -pub fn approve2( +pub fn approve_checked( token_program_id: &Pubkey, source_pubkey: &Pubkey, mint_pubkey: &Pubkey, @@ -955,7 +955,7 @@ pub fn approve2( amount: u64, decimals: u8, ) -> Result { - let data = TokenInstruction::Approve2 { amount, decimals }.pack(); + let data = TokenInstruction::ApproveChecked { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*source_pubkey, false)); @@ -976,8 +976,8 @@ pub fn approve2( }) } -/// Creates a `MintTo2` instruction. -pub fn mint_to2( +/// Creates a `MintToChecked` instruction. +pub fn mint_to_checked( token_program_id: &Pubkey, mint_pubkey: &Pubkey, account_pubkey: &Pubkey, @@ -986,7 +986,7 @@ pub fn mint_to2( amount: u64, decimals: u8, ) -> Result { - let data = TokenInstruction::MintTo2 { amount, decimals }.pack(); + let data = TokenInstruction::MintToChecked { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*mint_pubkey, false)); @@ -1006,8 +1006,8 @@ pub fn mint_to2( }) } -/// Creates a `Burn2` instruction. -pub fn burn2( +/// Creates a `BurnChecked` instruction. +pub fn burn_checked( token_program_id: &Pubkey, account_pubkey: &Pubkey, mint_pubkey: &Pubkey, @@ -1016,7 +1016,7 @@ pub fn burn2( amount: u64, decimals: u8, ) -> Result { - let data = TokenInstruction::Burn2 { amount, decimals }.pack(); + let data = TokenInstruction::BurnChecked { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); accounts.push(AccountMeta::new(*account_pubkey, false)); @@ -1156,7 +1156,7 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); - let check = TokenInstruction::Transfer2 { + let check = TokenInstruction::TransferChecked { amount: 1, decimals: 2, }; @@ -1166,7 +1166,7 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); - let check = TokenInstruction::Approve2 { + let check = TokenInstruction::ApproveChecked { amount: 1, decimals: 2, }; @@ -1176,7 +1176,7 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); - let check = TokenInstruction::MintTo2 { + let check = TokenInstruction::MintToChecked { amount: 1, decimals: 2, }; @@ -1186,7 +1186,7 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); - let check = TokenInstruction::Burn2 { + let check = TokenInstruction::BurnChecked { amount: 1, decimals: 2, }; diff --git a/program/src/processor.rs b/program/src/processor.rs index 7c32213..87bdb41 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -680,20 +680,20 @@ impl Processor { info!("Instruction: FreezeAccount"); Self::process_toggle_freeze_account(program_id, accounts, false) } - TokenInstruction::Transfer2 { amount, decimals } => { - info!("Instruction: Transfer"); + TokenInstruction::TransferChecked { amount, decimals } => { + info!("Instruction: TransferChecked"); Self::process_transfer(program_id, accounts, amount, Some(decimals)) } - TokenInstruction::Approve2 { amount, decimals } => { - info!("Instruction: Approve"); + TokenInstruction::ApproveChecked { amount, decimals } => { + info!("Instruction: ApproveChecked"); Self::process_approve(program_id, accounts, amount, Some(decimals)) } - TokenInstruction::MintTo2 { amount, decimals } => { - info!("Instruction: MintTo"); + TokenInstruction::MintToChecked { amount, decimals } => { + info!("Instruction: MintToChecked"); Self::process_mint_to(program_id, accounts, amount, Some(decimals)) } - TokenInstruction::Burn2 { amount, decimals } => { - info!("Instruction: Burn"); + TokenInstruction::BurnChecked { amount, decimals } => { + info!("Instruction: BurnChecked"); Self::process_burn(program_id, accounts, amount, Some(decimals)) } } @@ -1196,9 +1196,9 @@ mod tests { ) .unwrap(); - // source-owner transfer2 + // source-owner TransferChecked do_process_instruction_dups( - transfer2( + transfer_checked( &program_id, &account1_key, &mint_key, @@ -1244,9 +1244,9 @@ mod tests { ) .unwrap(); - // source-delegate transfer2 + // source-delegate TransferChecked do_process_instruction_dups( - transfer2( + transfer_checked( &program_id, &account1_key, &mint_key, @@ -1303,9 +1303,9 @@ mod tests { ) .unwrap(); - // destination-owner transfer2 + // destination-owner TransferChecked do_process_instruction_dups( - transfer2( + transfer_checked( &program_id, &account3_key, &mint_key, @@ -1373,9 +1373,9 @@ mod tests { ) .unwrap(); - // source-multisig-signer transfer2 + // source-multisig-signer TransferChecked do_process_instruction_dups( - transfer2( + transfer_checked( &program_id, &account4_key, &mint_key, @@ -1621,7 +1621,7 @@ mod tests { assert_eq!( Err(TokenError::MintDecimalsMismatch.into()), do_process_instruction( - transfer2( + transfer_checked( &program_id, &account2_key, &mint_key, @@ -1645,7 +1645,7 @@ mod tests { assert_eq!( Err(TokenError::MintMismatch.into()), do_process_instruction( - transfer2( + transfer_checked( &program_id, &account2_key, &account3_key, // <-- incorrect mint @@ -1666,7 +1666,7 @@ mod tests { ); // transfer rest with explicit decimals do_process_instruction( - transfer2( + transfer_checked( &program_id, &account2_key, &mint_key, @@ -1914,7 +1914,7 @@ mod tests { assert_eq!( Err(TokenError::MintDecimalsMismatch.into()), do_process_instruction( - mint_to2( + mint_to_checked( &program_id, &mint_key, &account_key, @@ -1934,7 +1934,7 @@ mod tests { // mint to 2 do_process_instruction( - mint_to2( + mint_to_checked( &program_id, &mint_key, &account_key, @@ -2051,9 +2051,9 @@ mod tests { ) .unwrap(); - // source-owner approve2 + // source-owner approve_checked do_process_instruction_dups( - approve2( + approve_checked( &program_id, &account1_key, &mint_key, @@ -2128,9 +2128,9 @@ mod tests { ) .unwrap(); - // source-multisig-signer approve2 + // source-multisig-signer approve_checked do_process_instruction_dups( - approve2( + approve_checked( &program_id, &account3_key, &mint_key, @@ -2294,7 +2294,7 @@ mod tests { assert_eq!( Err(TokenError::MintDecimalsMismatch.into()), do_process_instruction( - approve2( + approve_checked( &program_id, &account_key, &mint_key, @@ -2318,7 +2318,7 @@ mod tests { assert_eq!( Err(TokenError::MintMismatch.into()), do_process_instruction( - approve2( + approve_checked( &program_id, &account_key, &account2_key, // <-- bad mint @@ -2340,7 +2340,7 @@ mod tests { // approve delegate 2 do_process_instruction( - approve2( + approve_checked( &program_id, &account_key, &mint_key, @@ -2857,9 +2857,9 @@ mod tests { ) .unwrap(); - // mint_to2 when mint_authority is self + // mint_to_checked when mint_authority is self do_process_instruction_dups( - mint_to2(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), + mint_to_checked(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], ) .unwrap(); @@ -2886,7 +2886,7 @@ mod tests { ) .unwrap(); - // mint_to2 when mint_authority is account owner + // mint_to_checked when mint_authority is account owner do_process_instruction_dups( mint_to( &program_id, @@ -3175,9 +3175,9 @@ mod tests { ) .unwrap(); - // source-owner burn2 + // source-owner burn_checked do_process_instruction_dups( - burn2( + burn_checked( &program_id, &account1_key, &mint_key, @@ -3210,9 +3210,9 @@ mod tests { ) .unwrap(); - // mint-owner burn2 + // mint-owner burn_checked do_process_instruction_dups( - burn2( + burn_checked( &program_id, &account1_key, &mint_key, @@ -3255,9 +3255,9 @@ mod tests { ) .unwrap(); - // source-delegate burn2 + // source-delegate burn_checked do_process_instruction_dups( - burn2( + burn_checked( &program_id, &account1_key, &mint_key, @@ -3292,9 +3292,9 @@ mod tests { ) .unwrap(); - // mint-delegate burn2 + // mint-delegate burn_checked do_process_instruction_dups( - burn2( + burn_checked( &program_id, &account1_key, &mint_key, @@ -3461,18 +3461,18 @@ mod tests { ) .unwrap(); - // burn2, with incorrect decimals + // burn_checked, with incorrect decimals assert_eq!( Err(TokenError::MintDecimalsMismatch.into()), do_process_instruction( - burn2(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), + burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], ) ); - // burn2 + // burn_checked do_process_instruction( - burn2(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), + burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], ) .unwrap(); From 70032fdcfbb4370c48e657d840caac943c845a5b Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Fri, 25 Sep 2020 18:14:37 -0600 Subject: [PATCH 081/335] token: Bump solana crates to 1.3.14 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 9be3b68..fb39770 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,7 +21,7 @@ default = ["solana-sdk/default"] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.12", default-features = false, optional = true } +solana-sdk = { version = "1.3.14", default-features = false, optional = true } thiserror = "1.0" arrayref = "0.3.6" num_enum = "0.5.1" From 2bdced4972bc1a6063534e5398eaf339ac840f52 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 5 Oct 2020 21:12:45 -0600 Subject: [PATCH 082/335] Bump token to published version --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index fb39770..e3857fb 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "2.0.5" +version = "2.0.6" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From b9caba11c8a93cd35c7c51c13db8db10e6387008 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 5 Oct 2020 22:06:24 -0700 Subject: [PATCH 083/335] solana sdk does not need skip-no-mangle --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index e3857fb..281550b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -13,7 +13,7 @@ exclude = ["js/**"] [features] no-entrypoint = [] -skip-no-mangle = ["solana-sdk/skip-no-mangle"] +skip-no-mangle = [] program = ["solana-sdk/program"] default = ["solana-sdk/default"] From 010558725bf6dbdf55a940644d4cb7a33bf756da Mon Sep 17 00:00:00 2001 From: Jack May Date: Tue, 6 Oct 2020 13:45:20 -0700 Subject: [PATCH 084/335] Remove skip-no-mangle entirely --- program/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 281550b..d2b429e 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -13,7 +13,6 @@ exclude = ["js/**"] [features] no-entrypoint = [] -skip-no-mangle = [] program = ["solana-sdk/program"] default = ["solana-sdk/default"] From eab2181b156b36c60af3c057f73ed7b07013bbaf Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 15 Oct 2020 12:20:23 -0600 Subject: [PATCH 085/335] Bump memo and token versions (#627) --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index d2b429e..d22324e 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "spl-token" -version = "2.0.6" +version = "2.0.8" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" @@ -20,7 +20,7 @@ default = ["solana-sdk/default"] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.14", default-features = false, optional = true } +solana-sdk = { version = "1.3.17", default-features = false, optional = true } thiserror = "1.0" arrayref = "0.3.6" num_enum = "0.5.1" From 73fa260f38ae9a6683bebda6f068d5ce83d88a9d Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 19 Oct 2020 08:48:37 -0700 Subject: [PATCH 086/335] Add additional transfer test coverage --- program/src/processor.rs | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/program/src/processor.rs b/program/src/processor.rs index 87bdb41..ac83ca8 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1721,6 +1721,49 @@ mod tests { let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 1000); + // bogus transfer to self using system accounts. + // + // Transfer will succeed if the source and destination accounts have the same address, + // regardless of whether it is a valid token account. + // + // This is probably wrong but transactions in the wild have been observed to do this so + // this behavior is now part of the token ABI + { + let system_account_key = pubkey_rand(); + let mut system_account = SolanaAccount::new(1, 0, &Pubkey::default()); + + let instruction = transfer( + &program_id, + &system_account_key, + &system_account_key, + &owner_key, + &[], + 500, + ) + .unwrap(); + + let account_account_info = AccountInfo::from(( + &instruction.accounts[0].pubkey, + instruction.accounts[0].is_signer, + &mut system_account, + )); + let owner_account_info = AccountInfo::from(( + &instruction.accounts[2].pubkey, + instruction.accounts[2].is_signer, + &mut owner_account, + )); + Processor::process( + &instruction.program_id, + &[ + account_account_info.clone(), + account_account_info, + owner_account_info, + ], + &instruction.data, + ) + .unwrap() + } + // insufficient funds assert_eq!( Err(TokenError::InsufficientFunds.into()), From 0362b26e510c9713e6fe9ced4c19f5bf6e539a05 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 22 Oct 2020 21:44:27 -0700 Subject: [PATCH 087/335] Port SPL to solana-program and `cargo build-bpf` --- program/Cargo.toml | 10 +- program/src/entrypoint.rs | 5 +- program/src/error.rs | 2 +- program/src/instruction.rs | 2 +- program/src/lib.rs | 11 +- program/src/native_mint.rs | 4 +- program/src/processor.rs | 306 ++++++++++++++++++------------------- program/src/state.rs | 2 +- 8 files changed, 163 insertions(+), 179 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index d22324e..6e20a1a 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,3 @@ - -# Note: This crate must be built using do.sh - [package] name = "spl-token" version = "2.0.8" @@ -12,21 +9,18 @@ edition = "2018" exclude = ["js/**"] [features] -no-entrypoint = [] -program = ["solana-sdk/program"] -default = ["solana-sdk/default"] +exclude_entrypoint = [] [dependencies] num-derive = "0.3" num-traits = "0.2" remove_dir_all = "=0.5.0" -solana-sdk = { version = "1.3.17", default-features = false, optional = true } +solana-program = "1.4.3" thiserror = "1.0" arrayref = "0.3.6" num_enum = "0.5.1" [dev-dependencies] -rand = { version = "0.7.0"} [lib] crate-type = ["cdylib", "lib"] diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs index b5594ca..b255513 100644 --- a/program/src/entrypoint.rs +++ b/program/src/entrypoint.rs @@ -1,10 +1,7 @@ //! Program entrypoint -#![cfg(feature = "program")] -#![cfg(not(feature = "no-entrypoint"))] - use crate::{error::TokenError, processor::Processor}; -use solana_sdk::{ +use solana_program::{ account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, program_error::PrintProgramError, pubkey::Pubkey, }; diff --git a/program/src/error.rs b/program/src/error.rs index 32cd9d2..8305eaa 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -1,7 +1,7 @@ //! Error types use num_derive::FromPrimitive; -use solana_sdk::{decode_error::DecodeError, program_error::ProgramError}; +use solana_program::{decode_error::DecodeError, program_error::ProgramError}; use thiserror::Error; /// Errors that may be returned by the Token program. diff --git a/program/src/instruction.rs b/program/src/instruction.rs index de75b73..1d26643 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -1,7 +1,7 @@ //! Instruction types use crate::error::TokenError; -use solana_sdk::{ +use solana_program::{ instruction::{AccountMeta, Instruction}, program_error::ProgramError, program_option::COption, diff --git a/program/src/lib.rs b/program/src/lib.rs index 6e7108f..fc9707d 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -3,16 +3,17 @@ //! An ERC20-like Token program for the Solana blockchain -pub mod entrypoint; pub mod error; pub mod instruction; pub mod native_mint; pub mod processor; pub mod state; -// Export current solana-sdk types for downstream users who may also be building with a different -// solana-sdk version -pub use solana_sdk; +#[cfg(not(feature = "exclude_entrypoint"))] +mod entrypoint; + +// Export current sdk types for downstream users building with a different sdk version +pub use solana_program; /// Convert the UI representation of a token amount (using the decimals field defined in its mint) /// to the raw amount @@ -25,4 +26,4 @@ pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { amount as f64 / 10_usize.pow(decimals as u32) as f64 } -solana_sdk::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); +solana_program::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs index 740b8ab..0502f9f 100644 --- a/program/src/native_mint.rs +++ b/program/src/native_mint.rs @@ -4,12 +4,12 @@ pub const DECIMALS: u8 = 9; // The Mint for native SOL Token accounts -solana_sdk::declare_id!("So11111111111111111111111111111111111111112"); +solana_program::declare_id!("So11111111111111111111111111111111111111112"); #[cfg(test)] mod tests { use super::*; - use solana_sdk::native_token::*; + use solana_program::native_token::*; #[test] fn test_decimals() { diff --git a/program/src/processor.rs b/program/src/processor.rs index ac83ca8..c9b5e10 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1,6 +1,6 @@ //! Program state processor -#![cfg(feature = "program")] +//#![cfg(feature = "program")] use crate::{ error::TokenError, @@ -8,7 +8,7 @@ use crate::{ state::{Account, AccountState, Mint, Multisig}, }; use num_traits::FromPrimitive; -use solana_sdk::{ +use solana_program::{ account_info::{next_account_info, AccountInfo}, decode_error::DecodeError, entrypoint::ProgramResult, @@ -780,23 +780,15 @@ impl PrintProgramError for TokenError { } } -// Pull in syscall stubs when building for non-BPF targets -#[cfg(not(target_arch = "bpf"))] -solana_sdk::program_stubs!(); - #[cfg(test)] mod tests { use super::*; use crate::instruction::*; - use solana_sdk::{ + use solana_program::{ account::Account as SolanaAccount, account_info::create_is_signer_account_infos, clock::Epoch, instruction::Instruction, sysvar::rent, }; - fn pubkey_rand() -> Pubkey { - Pubkey::new(&rand::random::<[u8; 32]>()) - } - fn do_process_instruction( instruction: Instruction, accounts: Vec<&mut SolanaAccount>, @@ -968,11 +960,11 @@ mod tests { #[test] fn test_initialize_mint() { - let program_id = pubkey_rand(); - let owner_key = pubkey_rand(); - let mint_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); - let mint2_key = pubkey_rand(); + let mint2_key = Pubkey::new_unique(); let mut mint2_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); @@ -1016,12 +1008,12 @@ mod tests { #[test] fn test_initialize_mint_account() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); @@ -1092,46 +1084,46 @@ mod tests { #[test] fn test_transfer_dups() { - let program_id = pubkey_rand(); - let account1_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = pubkey_rand(); + let account3_key = Pubkey::new_unique(); let mut account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into(); - let account4_key = pubkey_rand(); + let account4_key = Pubkey::new_unique(); let mut account4_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into(); - let multisig_key = pubkey_rand(); + let multisig_key = Pubkey::new_unique(); let mut multisig_account = SolanaAccount::new( multisig_minimum_balance(), Multisig::get_packed_len(), &program_id, ); let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); @@ -1399,41 +1391,41 @@ mod tests { #[test] fn test_transfer() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account3_key = pubkey_rand(); + let account3_key = Pubkey::new_unique(); let mut account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let delegate_key = pubkey_rand(); + let delegate_key = Pubkey::new_unique(); let mut delegate_account = SolanaAccount::default(); - let mismatch_key = pubkey_rand(); + let mismatch_key = Pubkey::new_unique(); let mut mismatch_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = pubkey_rand(); + let mint2_key = Pubkey::new_unique(); let mut rent_sysvar = rent_sysvar(); // create mint @@ -1729,7 +1721,7 @@ mod tests { // This is probably wrong but transactions in the wild have been observed to do this so // this behavior is now part of the token ABI { - let system_account_key = pubkey_rand(); + let system_account_key = Pubkey::new_unique(); let mut system_account = SolanaAccount::new(1, 0, &Pubkey::default()); let instruction = transfer( @@ -1898,16 +1890,16 @@ mod tests { #[test] fn test_mintable_token_with_zero_supply() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); @@ -1949,7 +1941,7 @@ mod tests { vec![&mut mint_account, &mut account_account, &mut owner_account], ) .unwrap(); - let _ = Mint::unpack(&mut mint_account.data).unwrap(); + let _ = Mint::unpack(&mint_account.data).unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 42); @@ -1971,7 +1963,7 @@ mod tests { ) ); - let _ = Mint::unpack(&mut mint_account.data).unwrap(); + let _ = Mint::unpack(&mint_account.data).unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 42); @@ -1990,46 +1982,46 @@ mod tests { vec![&mut mint_account, &mut account_account, &mut owner_account], ) .unwrap(); - let _ = Mint::unpack(&mut mint_account.data).unwrap(); + let _ = Mint::unpack(&mint_account.data).unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 84); } #[test] fn test_approve_dups() { - let program_id = pubkey_rand(); - let account1_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = pubkey_rand(); + let account3_key = Pubkey::new_unique(); let mut account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into(); - let multisig_key = pubkey_rand(); + let multisig_key = Pubkey::new_unique(); let mut multisig_account = SolanaAccount::new( multisig_minimum_balance(), Multisig::get_packed_len(), &program_id, ); let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); @@ -2208,26 +2200,26 @@ mod tests { #[test] fn test_approve() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let delegate_key = pubkey_rand(); + let delegate_key = Pubkey::new_unique(); let mut delegate_account = SolanaAccount::default(); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); @@ -2413,16 +2405,16 @@ mod tests { #[test] fn test_set_authority_dups() { - let program_id = pubkey_rand(); - let account1_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = pubkey_rand(); - let mint_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); @@ -2516,28 +2508,28 @@ mod tests { #[test] fn test_set_authority() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); - let owner3_key = pubkey_rand(); - let mint_key = pubkey_rand(); + let owner3_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = pubkey_rand(); + let mint2_key = Pubkey::new_unique(); let mut mint2_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); @@ -2855,18 +2847,18 @@ mod tests { #[test] fn test_mint_to_dups() { - let program_id = pubkey_rand(); - let account1_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); @@ -2951,40 +2943,40 @@ mod tests { #[test] fn test_mint_to() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account3_key = pubkey_rand(); + let account3_key = Pubkey::new_unique(); let mut account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let mismatch_key = pubkey_rand(); + let mismatch_key = Pubkey::new_unique(); let mut mismatch_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = pubkey_rand(); - let uninitialized_key = pubkey_rand(); + let mint2_key = Pubkey::new_unique(); + let uninitialized_key = Pubkey::new_unique(); let mut uninitialized_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), @@ -3154,18 +3146,18 @@ mod tests { #[test] fn test_burn_dups() { - let program_id = pubkey_rand(); - let account1_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); @@ -3354,41 +3346,41 @@ mod tests { #[test] fn test_burn() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account3_key = pubkey_rand(); + let account3_key = Pubkey::new_unique(); let mut account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let delegate_key = pubkey_rand(); + let delegate_key = Pubkey::new_unique(); let mut delegate_account = SolanaAccount::default(); - let mismatch_key = pubkey_rand(); + let mismatch_key = Pubkey::new_unique(); let mut mismatch_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = pubkey_rand(); + let mint2_key = Pubkey::new_unique(); let mut rent_sysvar = rent_sysvar(); // create new mint @@ -3619,34 +3611,34 @@ mod tests { #[test] fn test_multisig() { - let program_id = pubkey_rand(); - let mint_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = pubkey_rand(); + let account_key = Pubkey::new_unique(); let mut account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let multisig_key = pubkey_rand(); + let multisig_key = Pubkey::new_unique(); let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id); - let multisig_delegate_key = pubkey_rand(); + let multisig_delegate_key = Pubkey::new_unique(); let mut multisig_delegate_account = SolanaAccount::new( multisig_minimum_balance(), Multisig::get_packed_len(), &program_id, ); - let signer_keys = vec![pubkey_rand(); MAX_SIGNERS]; - let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().map(|key| key).collect(); + let signer_keys = vec![Pubkey::new_unique(); MAX_SIGNERS]; + let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().collect(); let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; let mut rent_sysvar = rent_sysvar(); @@ -3911,13 +3903,13 @@ mod tests { .unwrap(); // freeze account - let account3_key = pubkey_rand(); + let account3_key = Pubkey::new_unique(); let mut account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let mint2_key = pubkey_rand(); + let mint2_key = Pubkey::new_unique(); let mut mint2_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); do_process_instruction( @@ -4023,11 +4015,11 @@ mod tests { #[test] fn test_validate_owner() { - let program_id = pubkey_rand(); - let owner_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let owner_key = Pubkey::new_unique(); let mut signer_keys = [Pubkey::default(); MAX_SIGNERS]; for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) { - *signer_key = pubkey_rand(); + *signer_key = Pubkey::new_unique(); } let mut signer_lamports = 0; let mut signer_data = vec![]; @@ -4183,23 +4175,23 @@ mod tests { #[test] fn test_close_account_dups() { - let program_id = pubkey_rand(); - let account1_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account2_info: AccountInfo = (&account2_key, true, &mut account2_account).into(); - let owner_key = pubkey_rand(); - let mint_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); @@ -4269,31 +4261,31 @@ mod tests { #[test] fn test_close_account() { - let program_id = pubkey_rand(); - let mint_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = pubkey_rand(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance() + 42, Account::get_packed_len(), &program_id, ); - let account3_key = pubkey_rand(); + let account3_key = Pubkey::new_unique(); let mut account3_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); let mut rent_sysvar = rent_sysvar(); @@ -4410,13 +4402,13 @@ mod tests { assert_eq!(account.amount, 0); // fund and initialize new non-native account to test close authority - let account_key = pubkey_rand(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), @@ -4498,24 +4490,24 @@ mod tests { #[test] fn test_native_token() { - let program_id = pubkey_rand(); + let program_id = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = pubkey_rand(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance() + 40, Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account3_key = pubkey_rand(); + let account3_key = Pubkey::new_unique(); let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); let mut rent_sysvar = rent_sysvar(); @@ -4579,7 +4571,7 @@ mod tests { ); // burn unsupported - let bogus_mint_key = pubkey_rand(); + let bogus_mint_key = Pubkey::new_unique(); let mut bogus_mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); do_process_instruction( @@ -4675,26 +4667,26 @@ mod tests { #[test] fn test_overflow() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); - let mint_owner_key = pubkey_rand(); + let mint_owner_key = Pubkey::new_unique(); let mut mint_owner_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); @@ -4852,22 +4844,22 @@ mod tests { #[test] fn test_frozen() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account2_key = pubkey_rand(); + let account2_key = Pubkey::new_unique(); let mut account2_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); @@ -4964,7 +4956,7 @@ mod tests { let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); account.state = AccountState::Frozen; Account::pack(account, &mut account_account.data).unwrap(); - let delegate_key = pubkey_rand(); + let delegate_key = Pubkey::new_unique(); let mut delegate_account = SolanaAccount::default(); assert_eq!( Err(TokenError::AccountFrozen.into()), @@ -5000,7 +4992,7 @@ mod tests { ); // no set authority if account is frozen - let new_owner_key = pubkey_rand(); + let new_owner_key = Pubkey::new_unique(); assert_eq!( Err(TokenError::AccountFrozen.into()), do_process_instruction( @@ -5038,16 +5030,16 @@ mod tests { #[test] fn test_freeze_thaw_dups() { - let program_id = pubkey_rand(); - let account1_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = pubkey_rand(); - let mint_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); @@ -5102,20 +5094,20 @@ mod tests { #[test] fn test_freeze_account() { - let program_id = pubkey_rand(); - let account_key = pubkey_rand(); + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), Account::get_packed_len(), &program_id, ); - let account_owner_key = pubkey_rand(); + let account_owner_key = Pubkey::new_unique(); let mut account_owner_account = SolanaAccount::default(); - let owner_key = pubkey_rand(); + let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); - let owner2_key = pubkey_rand(); + let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); - let mint_key = pubkey_rand(); + let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let mut rent_sysvar = rent_sysvar(); diff --git a/program/src/state.rs b/program/src/state.rs index 3622471..c35f342 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -3,7 +3,7 @@ use crate::instruction::MAX_SIGNERS; use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; use num_enum::TryFromPrimitive; -use solana_sdk::{ +use solana_program::{ program_error::ProgramError, program_option::COption, program_pack::{IsInitialized, Pack, Sealed}, From 1117b7840e59d17d8af387162156b94aa8e21773 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 26 Oct 2020 10:24:04 -0700 Subject: [PATCH 088/335] Refer to CreateAccount --- program/src/instruction.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 1d26643..ad205af 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -23,7 +23,7 @@ pub enum TokenInstruction { /// Initializes a new mint and optionally deposits all the newly minted tokens in an account. /// /// The `InitializeMint` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// the same Transaction as the system program's `CreateAccount` instruction that creates the account /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. /// /// Accounts expected by this instruction: @@ -45,7 +45,7 @@ pub enum TokenInstruction { /// initialized before this command can succeed. /// /// The `InitializeAccount` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// the same Transaction as the system program's `CreateAccount` instruction that creates the account /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. /// /// Accounts expected by this instruction: @@ -62,7 +62,7 @@ pub enum TokenInstruction { /// number of signers (M) required to validate this multisignature account. /// /// The `InitializeMultisig` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateInstruction` that creates the account + /// the same Transaction as the system program's `CreateAccount` instruction that creates the account /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. /// /// Accounts expected by this instruction: From 4152b691be312b742777040cc0eb87c0d1f368ba Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 26 Oct 2020 18:04:39 -0700 Subject: [PATCH 089/335] reformat token instruction comments (#732) --- program/src/instruction.rs | 111 ++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index ad205af..05d2d50 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -20,11 +20,14 @@ pub const MAX_SIGNERS: usize = 11; #[repr(C)] #[derive(Clone, Debug, PartialEq)] pub enum TokenInstruction { - /// Initializes a new mint and optionally deposits all the newly minted tokens in an account. + /// Initializes a new mint and optionally deposits all the newly minted + /// tokens in an account. /// - /// The `InitializeMint` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateAccount` instruction that creates the account - /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// The `InitializeMint` instruction requires no signers and MUST be + /// included within the same Transaction as the system program's + /// `CreateAccount` instruction that creates the account being initialized. + /// Otherwise another party can acquire ownership of the uninitialized + /// account. /// /// Accounts expected by this instruction: /// @@ -39,14 +42,17 @@ pub enum TokenInstruction { /// The freeze authority/multisignature of the mint. freeze_authority: COption, }, - /// Initializes a new account to hold tokens. If this account is associated with the native - /// mint then the token balance of the initialized account will be equal to the amount of SOL - /// in the account. If this account is associated with another mint, that mint must be - /// initialized before this command can succeed. + /// Initializes a new account to hold tokens. If this account is associated + /// with the native mint then the token balance of the initialized account + /// will be equal to the amount of SOL in the account. If this account is + /// associated with another mint, that mint must be initialized before this + /// command can succeed. /// - /// The `InitializeAccount` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateAccount` instruction that creates the account - /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// The `InitializeAccount` instruction requires no signers and MUST be + /// included within the same Transaction as the system program's + /// `CreateAccount` instruction that creates the account being initialized. + /// Otherwise another party can acquire ownership of the uninitialized + /// account. /// /// Accounts expected by this instruction: /// @@ -57,26 +63,32 @@ pub enum TokenInstruction { InitializeAccount, /// Initializes a multisignature account with N provided signers. /// - /// Multisignature accounts can used in place of any single owner/delegate accounts in any - /// token instruction that require an owner/delegate to be present. The variant field represents the - /// number of signers (M) required to validate this multisignature account. + /// Multisignature accounts can used in place of any single owner/delegate + /// accounts in any token instruction that require an owner/delegate to be + /// present. The variant field represents the number of signers (M) + /// required to validate this multisignature account. /// - /// The `InitializeMultisig` instruction requires no signers and MUST be included within - /// the same Transaction as the system program's `CreateAccount` instruction that creates the account - /// being initialized. Otherwise another party can acquire ownership of the uninitialized account. + /// The `InitializeMultisig` instruction requires no signers and MUST be + /// included within the same Transaction as the system program's + /// `CreateAccount` instruction that creates the account being initialized. + /// Otherwise another party can acquire ownership of the uninitialized + /// account. /// /// Accounts expected by this instruction: /// /// 0. `[writable]` The multisignature account to initialize. /// 1. `[]` Rent sysvar - /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= + /// 11. InitializeMultisig { - /// The number of signers (M) required to validate this multisignature account. + /// The number of signers (M) required to validate this multisignature + /// account. m: u8, }, - /// Transfers tokens from one account to another either directly or via a delegate. If this - /// account is associated with the native mint then equal amounts of SOL and Tokens will be - /// transferred to the destination account. + /// Transfers tokens from one account to another either directly or via a + /// delegate. If this account is associated with the native mint then equal + /// amounts of SOL and Tokens will be transferred to the destination + /// account. /// /// Accounts expected by this instruction: /// @@ -94,8 +106,8 @@ pub enum TokenInstruction { /// The amount of tokens to transfer. amount: u64, }, - /// Approves a delegate. A delegate is given the authority over - /// tokens on behalf of the source account's owner. + /// Approves a delegate. A delegate is given the authority over tokens on + /// behalf of the source account's owner. /// /// Accounts expected by this instruction: /// @@ -144,7 +156,8 @@ pub enum TokenInstruction { /// The new authority new_authority: COption, }, - /// Mints new tokens to an account. The native mint does not support minting. + /// Mints new tokens to an account. The native mint does not support + /// minting. /// /// Accounts expected by this instruction: /// @@ -162,8 +175,8 @@ pub enum TokenInstruction { /// The amount of new tokens to mint. amount: u64, }, - /// Burns tokens by removing them from an account. `Burn` does not support accounts - /// associated with the native mint, use `CloseAccount` instead. + /// Burns tokens by removing them from an account. `Burn` does not support + /// accounts associated with the native mint, use `CloseAccount` instead. /// /// Accounts expected by this instruction: /// @@ -197,7 +210,8 @@ pub enum TokenInstruction { /// 2. `[]` The account's multisignature owner. /// 3. ..3+M `[signer]` M signer accounts. CloseAccount, - /// Freeze an Initialized account using the Mint's freeze_authority (if set). + /// Freeze an Initialized account using the Mint's freeze_authority (if + /// set). /// /// Accounts expected by this instruction: /// @@ -228,13 +242,14 @@ pub enum TokenInstruction { /// 3. ..3+M `[signer]` M signer accounts. ThawAccount, - /// Transfers tokens from one account to another either directly or via a delegate. If this - /// account is associated with the native mint then equal amounts of SOL and Tokens will be - /// transferred to the destination account. + /// Transfers tokens from one account to another either directly or via a + /// delegate. If this account is associated with the native mint then equal + /// amounts of SOL and Tokens will be transferred to the destination + /// account. /// - /// This instruction differs from Transfer in that the token mint and decimals value is - /// checked by the caller. This may be useful when creating transactions offline or within a - /// hardware wallet. + /// This instruction differs from Transfer in that the token mint and + /// decimals value is checked by the caller. This may be useful when + /// creating transactions offline or within a hardware wallet. /// /// Accounts expected by this instruction: /// @@ -256,12 +271,12 @@ pub enum TokenInstruction { /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, - /// Approves a delegate. A delegate is given the authority over - /// tokens on behalf of the source account's owner. + /// Approves a delegate. A delegate is given the authority over tokens on + /// behalf of the source account's owner. /// - /// This instruction differs from Approve in that the token mint and decimals value is checked - /// by the caller. This may be useful when creating transactions offline or within a hardware - /// wallet. + /// This instruction differs from Approve in that the token mint and + /// decimals value is checked by the caller. This may be useful when + /// creating transactions offline or within a hardware wallet. /// /// Accounts expected by this instruction: /// @@ -283,10 +298,12 @@ pub enum TokenInstruction { /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, - /// Mints new tokens to an account. The native mint does not support minting. + /// Mints new tokens to an account. The native mint does not support + /// minting. /// - /// This instruction differs from MintTo in that the decimals value is checked by the - /// caller. This may be useful when creating transactions offline or within a hardware wallet. + /// This instruction differs from MintTo in that the decimals value is + /// checked by the caller. This may be useful when creating transactions + /// offline or within a hardware wallet. /// /// Accounts expected by this instruction: /// @@ -306,11 +323,13 @@ pub enum TokenInstruction { /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, - /// Burns tokens by removing them from an account. `BurnChecked` does not support accounts - /// associated with the native mint, use `CloseAccount` instead. + /// Burns tokens by removing them from an account. `BurnChecked` does not + /// support accounts associated with the native mint, use `CloseAccount` + /// instead. /// - /// This instruction differs from Burn in that the decimals value is checked by the caller. - /// This may be useful when creating transactions offline or within a hardware wallet. + /// This instruction differs from Burn in that the decimals value is checked + /// by the caller. This may be useful when creating transactions offline or + /// within a hardware wallet. /// /// Accounts expected by this instruction: /// From ed7b420d46043fe11a054d86672d70695f12adbb Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Sat, 31 Oct 2020 19:10:33 -0600 Subject: [PATCH 090/335] Clippy suggestions (#765) --- program/src/instruction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 05d2d50..21d712c 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -1057,7 +1057,7 @@ pub fn burn_checked( /// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS pub fn is_valid_signer_index(index: usize) -> bool { - !(index < MIN_SIGNERS || index > MAX_SIGNERS) + (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) } #[cfg(test)] From f1ae2261f1fec962f04e4b10c3d88ab695d0d7a2 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Sat, 31 Oct 2020 21:45:09 -0700 Subject: [PATCH 091/335] Update to solana v1.4.4 --- program/Cargo.toml | 8 ++++---- program/src/processor.rs | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 6e20a1a..c44e218 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -12,15 +12,15 @@ exclude = ["js/**"] exclude_entrypoint = [] [dependencies] +arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" -remove_dir_all = "=0.5.0" -solana-program = "1.4.3" -thiserror = "1.0" -arrayref = "0.3.6" num_enum = "0.5.1" +solana-program = "1.4.4" +thiserror = "1.0" [dev-dependencies] +solana-sdk = "1.4.4" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/src/processor.rs b/program/src/processor.rs index c9b5e10..da46e71 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1,7 +1,5 @@ //! Program state processor -//#![cfg(feature = "program")] - use crate::{ error::TokenError, instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, @@ -784,9 +782,9 @@ impl PrintProgramError for TokenError { mod tests { use super::*; use crate::instruction::*; - use solana_program::{ - account::Account as SolanaAccount, account_info::create_is_signer_account_infos, - clock::Epoch, instruction::Instruction, sysvar::rent, + use solana_program::{clock::Epoch, instruction::Instruction, sysvar::rent}; + use solana_sdk::account::{ + create_account, create_is_signer_account_infos, Account as SolanaAccount, }; fn do_process_instruction( @@ -816,7 +814,7 @@ mod tests { } fn rent_sysvar() -> SolanaAccount { - rent::create_account(42, &Rent::default()) + create_account(&Rent::default(), 42) } fn mint_minimum_balance() -> u64 { From 208b6f4c35e0b679c628180231951fcc96444774 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Sun, 1 Nov 2020 00:22:04 -0700 Subject: [PATCH 092/335] Drop lifetimes --- program/src/entrypoint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs index b255513..5331575 100644 --- a/program/src/entrypoint.rs +++ b/program/src/entrypoint.rs @@ -7,9 +7,9 @@ use solana_program::{ }; entrypoint!(process_instruction); -fn process_instruction<'a>( +fn process_instruction( program_id: &Pubkey, - accounts: &'a [AccountInfo<'a>], + accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { if let Err(error) = Processor::process(program_id, accounts, instruction_data) { From af82447bce230e242956a0953e14b67845c1916b Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Tue, 3 Nov 2020 09:33:32 -0800 Subject: [PATCH 093/335] Back to no-entrypoint feature name --- program/Cargo.toml | 2 +- program/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index c44e218..eb76c04 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" exclude = ["js/**"] [features] -exclude_entrypoint = [] +no-entrypoint = [] [dependencies] arrayref = "0.3.6" diff --git a/program/src/lib.rs b/program/src/lib.rs index fc9707d..a561e30 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -9,7 +9,7 @@ pub mod native_mint; pub mod processor; pub mod state; -#[cfg(not(feature = "exclude_entrypoint"))] +#[cfg(not(feature = "no-entrypoint"))] mod entrypoint; // Export current sdk types for downstream users building with a different sdk version From 9f313b0bea107668d3ef15cf7725c1df399c8b39 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 4 Nov 2020 10:29:16 -0800 Subject: [PATCH 094/335] Bump spl-token to v3.0.0 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index eb76c04..7f3860e 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "2.0.8" +version = "3.0.0" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 3d6a5cbabec2b15041e0bef86277df5d3afa26c0 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 4 Nov 2020 11:34:17 -0800 Subject: [PATCH 095/335] Limit docs.rs builds --- program/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/program/Cargo.toml b/program/Cargo.toml index 7f3860e..fcb7cd9 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -24,3 +24,6 @@ solana-sdk = "1.4.4" [lib] crate-type = ["cdylib", "lib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] From 7eaaccb2e3be2dbbf1c3498be0ce3bae00f4d241 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 6 Nov 2020 09:18:20 -0800 Subject: [PATCH 096/335] Bump solana version to v1.4.5 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index fcb7cd9..5057e12 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.4" +solana-program = "1.4.5" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.4.4" +solana-sdk = "1.4.5" [lib] crate-type = ["cdylib", "lib"] From 7a3cfca5d776c0127508cfd06094e8a1186f7432 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Nov 2020 12:39:52 +0000 Subject: [PATCH 097/335] Bump solana-program from 1.4.5 to 1.4.6 (#826) Bumps [solana-program](https://github.com/solana-labs/solana) from 1.4.5 to 1.4.6. - [Release notes](https://github.com/solana-labs/solana/releases) - [Changelog](https://github.com/solana-labs/solana/blob/master/RELEASE.md) - [Commits](https://github.com/solana-labs/solana/compare/v1.4.5...v1.4.6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 5057e12..5907704 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,7 +16,7 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.5" +solana-program = "1.4.6" thiserror = "1.0" [dev-dependencies] From 6fc2d5aaaa6d07404e2dbc4e4ec6679c4dc3f257 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 12 Nov 2020 09:19:39 -0800 Subject: [PATCH 098/335] Upgrade to Solana 1.4.7 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 5907704..3fc6997 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.6" +solana-program = "1.4.7" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.4.5" +solana-sdk = "1.4.7" [lib] crate-type = ["cdylib", "lib"] From 93eef00c68b65ff0c17894de2f68c60e857e02b2 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 13 Nov 2020 17:57:21 -0800 Subject: [PATCH 099/335] Update to Solana 1.4.8 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 3fc6997..8362665 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.7" +solana-program = "1.4.8" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.4.7" +solana-sdk = "1.4.8" [lib] crate-type = ["cdylib", "lib"] From aad1537b377b8ef3c28cde239efd347c01d40b76 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Tue, 17 Nov 2020 17:26:59 -0800 Subject: [PATCH 100/335] Bump solana version to v1.4.9 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 8362665..42e6318 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.8" +solana-program = "1.4.9" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.4.8" +solana-sdk = "1.4.9" [lib] crate-type = ["cdylib", "lib"] From 464c2616599e789053471d00d31a00ed4ea3a790 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Dec 2020 12:54:42 +0000 Subject: [PATCH 101/335] Bump solana-program from 1.4.9 to 1.4.13 (#916) Bumps [solana-program](https://github.com/solana-labs/solana) from 1.4.9 to 1.4.13. - [Release notes](https://github.com/solana-labs/solana/releases) - [Changelog](https://github.com/solana-labs/solana/blob/master/RELEASE.md) - [Commits](https://github.com/solana-labs/solana/compare/v1.4.9...v1.4.13) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 42e6318..d1c1b2f 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,7 +16,7 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.9" +solana-program = "1.4.13" thiserror = "1.0" [dev-dependencies] From f845d0d35319a6a18b0b2a5269cdd4a35ba95056 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 2 Dec 2020 18:37:53 -0800 Subject: [PATCH 102/335] Upgrade to Solana v1.4.14 --- program/Cargo.toml | 4 +-- program/src/processor.rs | 74 +++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index d1c1b2f..458201b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.13" +solana-program = "1.4.14" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.4.9" +solana-sdk = "1.4.14" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/src/processor.rs b/program/src/processor.rs index da46e71..a1476ba 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -10,7 +10,7 @@ use solana_program::{ account_info::{next_account_info, AccountInfo}, decode_error::DecodeError, entrypoint::ProgramResult, - info, + msg, program_error::{PrintProgramError, ProgramError}, program_option::COption, program_pack::{IsInitialized, Pack}, @@ -628,70 +628,70 @@ impl Processor { mint_authority, freeze_authority, } => { - info!("Instruction: InitializeMint"); + msg!("Instruction: InitializeMint"); Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority) } TokenInstruction::InitializeAccount => { - info!("Instruction: InitializeAccount"); + msg!("Instruction: InitializeAccount"); Self::process_initialize_account(accounts) } TokenInstruction::InitializeMultisig { m } => { - info!("Instruction: InitializeMultisig"); + msg!("Instruction: InitializeMultisig"); Self::process_initialize_multisig(accounts, m) } TokenInstruction::Transfer { amount } => { - info!("Instruction: Transfer"); + msg!("Instruction: Transfer"); Self::process_transfer(program_id, accounts, amount, None) } TokenInstruction::Approve { amount } => { - info!("Instruction: Approve"); + msg!("Instruction: Approve"); Self::process_approve(program_id, accounts, amount, None) } TokenInstruction::Revoke => { - info!("Instruction: Revoke"); + msg!("Instruction: Revoke"); Self::process_revoke(program_id, accounts) } TokenInstruction::SetAuthority { authority_type, new_authority, } => { - info!("Instruction: SetAuthority"); + msg!("Instruction: SetAuthority"); Self::process_set_authority(program_id, accounts, authority_type, new_authority) } TokenInstruction::MintTo { amount } => { - info!("Instruction: MintTo"); + msg!("Instruction: MintTo"); Self::process_mint_to(program_id, accounts, amount, None) } TokenInstruction::Burn { amount } => { - info!("Instruction: Burn"); + msg!("Instruction: Burn"); Self::process_burn(program_id, accounts, amount, None) } TokenInstruction::CloseAccount => { - info!("Instruction: CloseAccount"); + msg!("Instruction: CloseAccount"); Self::process_close_account(program_id, accounts) } TokenInstruction::FreezeAccount => { - info!("Instruction: FreezeAccount"); + msg!("Instruction: FreezeAccount"); Self::process_toggle_freeze_account(program_id, accounts, true) } TokenInstruction::ThawAccount => { - info!("Instruction: FreezeAccount"); + msg!("Instruction: FreezeAccount"); Self::process_toggle_freeze_account(program_id, accounts, false) } TokenInstruction::TransferChecked { amount, decimals } => { - info!("Instruction: TransferChecked"); + msg!("Instruction: TransferChecked"); Self::process_transfer(program_id, accounts, amount, Some(decimals)) } TokenInstruction::ApproveChecked { amount, decimals } => { - info!("Instruction: ApproveChecked"); + msg!("Instruction: ApproveChecked"); Self::process_approve(program_id, accounts, amount, Some(decimals)) } TokenInstruction::MintToChecked { amount, decimals } => { - info!("Instruction: MintToChecked"); + msg!("Instruction: MintToChecked"); Self::process_mint_to(program_id, accounts, amount, Some(decimals)) } TokenInstruction::BurnChecked { amount, decimals } => { - info!("Instruction: BurnChecked"); + msg!("Instruction: BurnChecked"); Self::process_burn(program_id, accounts, amount, Some(decimals)) } } @@ -741,38 +741,36 @@ impl PrintProgramError for TokenError { E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, { match self { - TokenError::NotRentExempt => { - info!("Error: Lamport balance below rent-exempt threshold") - } - TokenError::InsufficientFunds => info!("Error: insufficient funds"), - TokenError::InvalidMint => info!("Error: Invalid Mint"), - TokenError::MintMismatch => info!("Error: Account not associated with this Mint"), - TokenError::OwnerMismatch => info!("Error: owner does not match"), - TokenError::FixedSupply => info!("Error: the total supply of this token is fixed"), - TokenError::AlreadyInUse => info!("Error: account or token already in use"), + TokenError::NotRentExempt => msg!("Error: Lamport balance below rent-exempt threshold"), + TokenError::InsufficientFunds => msg!("Error: insufficient funds"), + TokenError::InvalidMint => msg!("Error: Invalid Mint"), + TokenError::MintMismatch => msg!("Error: Account not associated with this Mint"), + TokenError::OwnerMismatch => msg!("Error: owner does not match"), + TokenError::FixedSupply => msg!("Error: the total supply of this token is fixed"), + TokenError::AlreadyInUse => msg!("Error: account or token already in use"), TokenError::InvalidNumberOfProvidedSigners => { - info!("Error: Invalid number of provided signers") + msg!("Error: Invalid number of provided signers") } TokenError::InvalidNumberOfRequiredSigners => { - info!("Error: Invalid number of required signers") + msg!("Error: Invalid number of required signers") } - TokenError::UninitializedState => info!("Error: State is uninitialized"), + TokenError::UninitializedState => msg!("Error: State is uninitialized"), TokenError::NativeNotSupported => { - info!("Error: Instruction does not support native tokens") + msg!("Error: Instruction does not support native tokens") } TokenError::NonNativeHasBalance => { - info!("Error: Non-native account can only be closed if its balance is zero") + msg!("Error: Non-native account can only be closed if its balance is zero") } - TokenError::InvalidInstruction => info!("Error: Invalid instruction"), - TokenError::InvalidState => info!("Error: Invalid account state for operation"), - TokenError::Overflow => info!("Error: Operation overflowed"), + TokenError::InvalidInstruction => msg!("Error: Invalid instruction"), + TokenError::InvalidState => msg!("Error: Invalid account state for operation"), + TokenError::Overflow => msg!("Error: Operation overflowed"), TokenError::AuthorityTypeNotSupported => { - info!("Error: Account does not support specified authority type") + msg!("Error: Account does not support specified authority type") } - TokenError::MintCannotFreeze => info!("Error: This token mint cannot freeze accounts"), - TokenError::AccountFrozen => info!("Error: Account is frozen"), + TokenError::MintCannotFreeze => msg!("Error: This token mint cannot freeze accounts"), + TokenError::AccountFrozen => msg!("Error: Account is frozen"), TokenError::MintDecimalsMismatch => { - info!("Error: decimals different from the Mint decimals") + msg!("Error: decimals different from the Mint decimals") } } } From f97d5f8ff3eeef4f7966e2dacf545a94be4b06f1 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Wed, 16 Dec 2020 11:51:03 -0700 Subject: [PATCH 103/335] Bump {ata,memo,token-{program,cli}} to solana v1.4.17 To pick up cargo audit fixes for monorepo --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 458201b..4281b5a 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.14" +solana-program = "1.4.17" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.4.14" +solana-sdk = "1.4.17" [lib] crate-type = ["cdylib", "lib"] From 0e382c178f01f878336bd1354bd26982baedd2c4 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Wed, 16 Dec 2020 11:55:04 -0700 Subject: [PATCH 104/335] Bump token to v3.0.1 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 4281b5a..257d0a4 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.0.0" +version = "3.0.1" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From e1667fcad3051a0a009961ef9153024382a2e64e Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 17 Dec 2020 16:11:56 -0800 Subject: [PATCH 105/335] Update to Solana 1.5.0 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 257d0a4..294d2a5 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.4.17" +solana-program = "1.5.0" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.4.17" +solana-sdk = "1.5.0" [lib] crate-type = ["cdylib", "lib"] From 32a68d4647a9be69464ee0591464a28e0e71c144 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jan 2021 13:51:29 +0000 Subject: [PATCH 106/335] build(deps): bump solana-program from 1.5.0 to 1.5.1 (#1025) Bumps [solana-program](https://github.com/solana-labs/solana) from 1.5.0 to 1.5.1. - [Release notes](https://github.com/solana-labs/solana/releases) - [Changelog](https://github.com/solana-labs/solana/blob/master/RELEASE.md) - [Commits](https://github.com/solana-labs/solana/compare/v1.5.0...v1.5.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 294d2a5..8c66334 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,7 +16,7 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.5.0" +solana-program = "1.5.1" thiserror = "1.0" [dev-dependencies] From 57c975b4625fbae17411b55a8b4e898697679c1b Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Tue, 26 Jan 2021 20:15:08 -0700 Subject: [PATCH 107/335] token: Fully check self-transfers --- program/src/processor.rs | 69 ++++++++++------------------------------ 1 file changed, 16 insertions(+), 53 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index a1476ba..ceea0ff 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -152,10 +152,6 @@ impl Processor { let dest_account_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; - if source_account_info.key == dest_account_info.key { - return Ok(()); - } - let mut source_account = Account::unpack(&source_account_info.data.borrow())?; let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; @@ -180,6 +176,8 @@ impl Processor { } } + let self_transfer = source_account_info.key == dest_account_info.key; + match source_account.delegate { COption::Some(ref delegate) if authority_info.key == delegate => { Self::validate_owner( @@ -191,12 +189,14 @@ impl Processor { if source_account.delegated_amount < amount { return Err(TokenError::InsufficientFunds.into()); } - source_account.delegated_amount = source_account - .delegated_amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; + if !self_transfer { + source_account.delegated_amount = source_account + .delegated_amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } } } _ => Self::validate_owner( @@ -207,6 +207,12 @@ impl Processor { )?, }; + // This check MUST occur just before the amounts are manipulated + // to ensure self-transfers are fully validated + if self_transfer { + return Ok(()); + } + source_account.amount = source_account .amount .checked_sub(amount) @@ -1709,49 +1715,6 @@ mod tests { let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, 1000); - // bogus transfer to self using system accounts. - // - // Transfer will succeed if the source and destination accounts have the same address, - // regardless of whether it is a valid token account. - // - // This is probably wrong but transactions in the wild have been observed to do this so - // this behavior is now part of the token ABI - { - let system_account_key = Pubkey::new_unique(); - let mut system_account = SolanaAccount::new(1, 0, &Pubkey::default()); - - let instruction = transfer( - &program_id, - &system_account_key, - &system_account_key, - &owner_key, - &[], - 500, - ) - .unwrap(); - - let account_account_info = AccountInfo::from(( - &instruction.accounts[0].pubkey, - instruction.accounts[0].is_signer, - &mut system_account, - )); - let owner_account_info = AccountInfo::from(( - &instruction.accounts[2].pubkey, - instruction.accounts[2].is_signer, - &mut owner_account, - )); - Processor::process( - &instruction.program_id, - &[ - account_account_info.clone(), - account_account_info, - owner_account_info, - ], - &instruction.data, - ) - .unwrap() - } - // insufficient funds assert_eq!( Err(TokenError::InsufficientFunds.into()), From 7695e4d53126fdef7cf4ed626552ae2fb572871f Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Wed, 27 Jan 2021 22:54:01 -0700 Subject: [PATCH 108/335] token: Add a full suite of self-transfer tests --- program/src/processor.rs | 569 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 533 insertions(+), 36 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index ceea0ff..4ea40ae 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -786,7 +786,9 @@ impl PrintProgramError for TokenError { mod tests { use super::*; use crate::instruction::*; - use solana_program::{clock::Epoch, instruction::Instruction, sysvar::rent}; + use solana_program::{ + account_info::IntoAccountInfo, clock::Epoch, instruction::Instruction, sysvar::rent, + }; use solana_sdk::account::{ create_account, create_is_signer_account_infos, Account as SolanaAccount, }; @@ -1680,41 +1682,6 @@ mod tests { ) .unwrap(); - // transfer to self - { - let instruction = transfer( - &program_id, - &account_key, - &account_key, - &owner_key, - &[], - 500, - ) - .unwrap(); - let account_account_info = AccountInfo::from(( - &instruction.accounts[0].pubkey, - instruction.accounts[0].is_signer, - &mut account_account, - )); - let owner_account_info = AccountInfo::from(( - &instruction.accounts[2].pubkey, - instruction.accounts[2].is_signer, - &mut owner_account, - )); - Processor::process( - &instruction.program_id, - &[ - account_account_info.clone(), - account_account_info, - owner_account_info, - ], - &instruction.data, - ) - .unwrap() - } - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000); - // insufficient funds assert_eq!( Err(TokenError::InsufficientFunds.into()), @@ -1847,6 +1814,536 @@ mod tests { ); } + #[test] + fn test_self_transfer() { + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let account_info = (&account_key, false, &mut account_account).into_account_info(); + let account3_info = (&account3_key, false, &mut account3_account).into_account_info(); + let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info(); + let owner_info = (&owner_key, true, &mut owner_account).into_account_info(); + let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info(); + let mint_info = (&mint_key, false, &mut mint_account).into_account_info(); + + // transfer + let instruction = transfer( + &program_id, + &account_info.key, + &account_info.key, + &owner_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // transfer checked + let instruction = transfer_checked( + &program_id, + &account_info.key, + &mint_info.key, + &account_info.key, + &owner_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // missing signer + let mut owner_no_sign_info = owner_info.clone(); + let mut instruction = transfer( + &program_id, + &account_info.key, + &account_info.key, + &owner_no_sign_info.key, + &[], + 1000, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + owner_no_sign_info.is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_no_sign_info.clone(), + ], + &instruction.data, + ) + ); + + // missing signer checked + let mut instruction = transfer_checked( + &program_id, + &account_info.key, + &mint_info.key, + &account_info.key, + &owner_no_sign_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + instruction.accounts[3].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_no_sign_info, + ], + &instruction.data, + ) + ); + + // missing owner + let instruction = transfer( + &program_id, + &account_info.key, + &account_info.key, + &owner2_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner2_info.clone(), + ], + &instruction.data, + ) + ); + + // missing owner checked + let instruction = transfer_checked( + &program_id, + &account_info.key, + &mint_info.key, + &account_info.key, + &owner2_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner2_info.clone(), + ], + &instruction.data, + ) + ); + + // insufficient funds + let instruction = transfer( + &program_id, + &account_info.key, + &account_info.key, + &owner_info.key, + &[], + 1001, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // insufficient funds checked + let instruction = transfer_checked( + &program_id, + &account_info.key, + &mint_info.key, + &account_info.key, + &owner_info.key, + &[], + 1001, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // incorrect decimals + let instruction = transfer_checked( + &program_id, + &account_info.key, + &mint_info.key, + &account_info.key, + &owner_info.key, + &[], + 1, + 10, // <-- incorrect decimals + ) + .unwrap(); + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // incorrect mint + let instruction = transfer_checked( + &program_id, + &account_info.key, + &account3_info.key, // <-- incorrect mint + &account_info.key, + &owner_info.key, + &[], + 1, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::MintMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account3_info.clone(), // <-- incorrect mint + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // approve delegate + let instruction = approve( + &program_id, + &account_info.key, + &delegate_info.key, + &owner_info.key, + &[], + 100, + ) + .unwrap(); + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + delegate_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + .unwrap(); + + // delegate transfer + let instruction = transfer( + &program_id, + &account_info.key, + &account_info.key, + &delegate_info.key, + &[], + 100, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + assert_eq!(account.delegated_amount, 100); + + // delegate transfer checked + let instruction = transfer_checked( + &program_id, + &account_info.key, + &mint_info.key, + &account_info.key, + &delegate_info.key, + &[], + 100, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + assert_eq!(account.delegated_amount, 100); + + // delegate insufficient funds + let instruction = transfer( + &program_id, + &account_info.key, + &account_info.key, + &delegate_info.key, + &[], + 101, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + + // delegate insufficient funds checked + let instruction = transfer_checked( + &program_id, + &account_info.key, + &mint_info.key, + &account_info.key, + &delegate_info.key, + &[], + 101, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + + // owner transfer with delegate assigned + let instruction = transfer( + &program_id, + &account_info.key, + &account_info.key, + &owner_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // owner transfer with delegate assigned checked + let instruction = transfer_checked( + &program_id, + &account_info.key, + &mint_info.key, + &account_info.key, + &owner_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + } + #[test] fn test_mintable_token_with_zero_supply() { let program_id = Pubkey::new_unique(); From 6b6610dc6e613a21c07b1b8b902de25e3a66fa21 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Thu, 28 Jan 2021 16:31:35 -0700 Subject: [PATCH 109/335] token: Add InitializeAccount2 instruction Passes the owner as instruction data rather than on the accounts list, improving CPI ergonomics where the owner's `AccountInfo` isn't otherwise required --- program/src/instruction.rs | 59 ++++++++++++++++++++++++++++- program/src/processor.rs | 76 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 130 insertions(+), 5 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 21d712c..063eb7c 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -349,6 +349,20 @@ pub enum TokenInstruction { /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, + /// Like InitializeAccount, but the owner pubkey is passed via instruction data + /// rather than the accounts list. This variant may be preferable when using + /// Cross Program Invocation from an instruction that does not need the owner's + /// `AccountInfo` otherwise. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// 1. `[]` The mint this account will be associated with. + /// 3. `[]` Rent sysvar + InitializeAccount2 { + /// The new account's owner/multisignature. + owner: Pubkey, + }, } impl TokenInstruction { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). @@ -446,6 +460,10 @@ impl TokenInstruction { Self::BurnChecked { amount, decimals } } + 16 => { + let (owner, _rest) = Self::unpack_pubkey(rest)?; + Self::InitializeAccount2 { owner } + } _ => return Err(TokenError::InvalidInstruction.into()), }) @@ -518,6 +536,10 @@ impl TokenInstruction { buf.extend_from_slice(&amount.to_le_bytes()); buf.push(decimals); } + &Self::InitializeAccount2 { owner } => { + buf.push(16); + buf.extend_from_slice(owner.as_ref()); + } }; buf } @@ -625,7 +647,7 @@ pub fn initialize_account( mint_pubkey: &Pubkey, owner_pubkey: &Pubkey, ) -> Result { - let data = TokenInstruction::InitializeAccount.pack(); // TODO do we need to return result? + let data = TokenInstruction::InitializeAccount.pack(); let accounts = vec![ AccountMeta::new(*account_pubkey, false), @@ -641,6 +663,31 @@ pub fn initialize_account( }) } +/// Creates a `InitializeAccount2` instruction. +pub fn initialize_account2( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + owner_pubkey: &Pubkey, +) -> Result { + let data = TokenInstruction::InitializeAccount2 { + owner: *owner_pubkey, + } + .pack(); + + let accounts = vec![ + AccountMeta::new(*account_pubkey, false), + AccountMeta::new_readonly(*mint_pubkey, false), + AccountMeta::new_readonly(sysvar::rent::id(), false), + ]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + /// Creates a `InitializeMultisig` instruction. pub fn initialize_multisig( token_program_id: &Pubkey, @@ -1214,5 +1261,15 @@ mod test { assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeAccount2 { + owner: Pubkey::new(&[2u8; 32]), + }; + let packed = check.pack(); + let mut expect = vec![16u8]; + expect.extend_from_slice(&[2u8; 32]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); } } diff --git a/program/src/processor.rs b/program/src/processor.rs index 4ea40ae..5d22ca5 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -52,12 +52,18 @@ impl Processor { Ok(()) } - /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { + fn _process_initialize_account( + accounts: &[AccountInfo], + owner: Option<&Pubkey>, + ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let new_account_info = next_account_info(account_info_iter)?; let mint_info = next_account_info(account_info_iter)?; - let owner_info = next_account_info(account_info_iter)?; + let owner = if let Some(owner) = owner { + owner + } else { + next_account_info(account_info_iter)?.key + }; let new_account_info_data_len = new_account_info.data_len(); let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; @@ -76,7 +82,7 @@ impl Processor { } account.mint = *mint_info.key; - account.owner = *owner_info.key; + account.owner = *owner; account.delegate = COption::None; account.delegated_amount = 0; account.state = AccountState::Initialized; @@ -97,6 +103,16 @@ impl Processor { Ok(()) } + /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. + pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { + Self::_process_initialize_account(accounts, None) + } + + /// Processes an [InitializeAccount2](enum.TokenInstruction.html) instruction. + pub fn process_initialize_account2(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { + Self::_process_initialize_account(accounts, Some(&owner)) + } + /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -641,6 +657,10 @@ impl Processor { msg!("Instruction: InitializeAccount"); Self::process_initialize_account(accounts) } + TokenInstruction::InitializeAccount2 { owner } => { + msg!("Instruction: InitializeAccount2"); + Self::process_initialize_account2(accounts, owner) + } TokenInstruction::InitializeMultisig { m } => { msg!("Instruction: InitializeMultisig"); Self::process_initialize_multisig(accounts, m) @@ -5660,4 +5680,52 @@ mod tests { let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.state, AccountState::Initialized); } + + #[test] + fn test_initialize_account2() { + let program_id = Pubkey::new_unique(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + do_process_instruction( + initialize_account2(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + assert_eq!(account_account, account2_account); + } } From e4f0599aa73aa6813ac31670a637f158f9dcc309 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Fri, 5 Feb 2021 18:53:13 -0700 Subject: [PATCH 110/335] token: Wrap C bindings at 80 char --- program/inc/token.h | 111 ++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index 954d841..e027ac5 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -105,11 +105,14 @@ typedef struct Token_COption_Pubkey { */ typedef enum Token_TokenInstruction_Tag { /** - * Initializes a new mint and optionally deposits all the newly minted tokens in an account. + * Initializes a new mint and optionally deposits all the newly minted + * tokens in an account. * - * The `InitializeMint` instruction requires no signers and MUST be included within - * the same Transaction as the system program's `CreateInstruction` that creates the account - * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * The `InitializeMint` instruction requires no signers and MUST be + * included within the same Transaction as the system program's + * `CreateInstruction` that creates the account being initialized. + * Otherwise another party can acquire ownership of the uninitialized + * account. * * Accounts expected by this instruction: * @@ -119,14 +122,17 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_InitializeMint, /** - * Initializes a new account to hold tokens. If this account is associated with the native - * mint then the token balance of the initialized account will be equal to the amount of SOL - * in the account. If this account is associated with another mint, that mint must be - * initialized before this command can succeed. + * Initializes a new account to hold tokens. If this account is associated + * with the native mint then the token balance of the initialized account + * will be equal to the amount of SOL in the account. If this account is + * associated with another mint, that mint must be initialized before this + * command can succeed. * - * The `InitializeAccount` instruction requires no signers and MUST be included within - * the same Transaction as the system program's `CreateInstruction` that creates the account - * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * The `InitializeAccount` instruction requires no signers and MUST be + * included within the same Transaction as the system program's + * `CreateInstruction` that creates the account being initialized. + * Otherwise another party can acquire ownership of the uninitialized + * account. * * Accounts expected by this instruction: * @@ -139,25 +145,30 @@ typedef enum Token_TokenInstruction_Tag { /** * Initializes a multisignature account with N provided signers. * - * Multisignature accounts can used in place of any single owner/delegate accounts in any - * token instruction that require an owner/delegate to be present. The variant field represents the - * number of signers (M) required to validate this multisignature account. + * Multisignature accounts can used in place of any single owner/delegate + * accounts in any token instruction that require an owner/delegate to be + * present. The variant field represents the number of signers (M) + * required to validate this multisignature account. * - * The `InitializeMultisig` instruction requires no signers and MUST be included within - * the same Transaction as the system program's `CreateInstruction` that creates the account - * being initialized. Otherwise another party can acquire ownership of the uninitialized account. + * The `InitializeMultisig` instruction requires no signers and MUST be + * included within the same Transaction as the system program's + * `CreateInstruction` that creates the account being initialized. + * Otherwise another party can acquire ownership of the uninitialized + * account. * * Accounts expected by this instruction: * * 0. `[writable]` The multisignature account to initialize. * 1. `[]` Rent sysvar - * 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= 11. + * 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= + * 11. */ Token_TokenInstruction_InitializeMultisig, /** - * Transfers tokens from one account to another either directly or via a delegate. If this - * account is associated with the native mint then equal amounts of SOL and Tokens will be - * transferred to the destination account. + * Transfers tokens from one account to another either directly or via a + * delegate. If this account is associated with the native mint then equal + * amounts of SOL and Tokens will be transferred to the destination + * account. * * Accounts expected by this instruction: * @@ -174,8 +185,8 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_Transfer, /** - * Approves a delegate. A delegate is given the authority over - * tokens on behalf of the source account's owner. + * Approves a delegate. A delegate is given the authority over tokens on + * behalf of the source account's owner. * * Accounts expected by this instruction: * @@ -222,7 +233,8 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_SetAuthority, /** - * Mints new tokens to an account. The native mint does not support minting. + * Mints new tokens to an account. The native mint does not support + * minting. * * Accounts expected by this instruction: * @@ -239,8 +251,8 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_MintTo, /** - * Burns tokens by removing them from an account. `Burn` does not support accounts - * associated with the native mint, use `CloseAccount` instead. + * Burns tokens by removing them from an account. `Burn` does not support + * accounts associated with the native mint, use `CloseAccount` instead. * * Accounts expected by this instruction: * @@ -275,7 +287,8 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_CloseAccount, /** - * Freeze an Initialized account using the Mint's freeze_authority (if set). + * Freeze an Initialized account using the Mint's freeze_authority (if + * set). * * Accounts expected by this instruction: * @@ -309,13 +322,14 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_ThawAccount, /** - * Transfers tokens from one account to another either directly or via a delegate. If this - * account is associated with the native mint then equal amounts of SOL and Tokens will be - * transferred to the destination account. + * Transfers tokens from one account to another either directly or via a + * delegate. If this account is associated with the native mint then equal + * amounts of SOL and Tokens will be transferred to the destination + * account. * - * This instruction differs from Transfer in that the token mint and decimals value is - * asserted by the caller. This may be useful when creating transactions offline or within a - * hardware wallet. + * This instruction differs from Transfer in that the token mint and + * decimals value is asserted by the caller. This may be useful when + * creating transactions offline or within a hardware wallet. * * Accounts expected by this instruction: * @@ -334,12 +348,12 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_Transfer2, /** - * Approves a delegate. A delegate is given the authority over - * tokens on behalf of the source account's owner. + * Approves a delegate. A delegate is given the authority over tokens on + * behalf of the source account's owner. * - * This instruction differs from Approve in that the token mint and decimals value is asserted - * by the caller. This may be useful when creating transactions offline or within a hardware - * wallet. + * This instruction differs from Approve in that the token mint and + * decimals value is asserted by the caller. This may be useful when + * creating transactions offline or within a hardware wallet. * * Accounts expected by this instruction: * @@ -358,10 +372,12 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_Approve2, /** - * Mints new tokens to an account. The native mint does not support minting. + * Mints new tokens to an account. The native mint does not support + * minting. * - * This instruction differs from MintTo in that the decimals value is asserted by the - * caller. This may be useful when creating transactions offline or within a hardware wallet. + * This instruction differs from MintTo in that the decimals value is + * asserted by the caller. This may be useful when creating transactions + * offline or within a hardware wallet. * * Accounts expected by this instruction: * @@ -378,11 +394,13 @@ typedef enum Token_TokenInstruction_Tag { */ Token_TokenInstruction_MintTo2, /** - * Burns tokens by removing them from an account. `Burn2` does not support accounts - * associated with the native mint, use `CloseAccount` instead. + * Burns tokens by removing them from an account. `Burn2` does not + * support accounts associated with the native mint, use `CloseAccount` + * instead. * - * This instruction differs from Burn in that the decimals value is asserted by the caller. - * This may be useful when creating transactions offline or within a hardware wallet. + * This instruction differs from Burn in that the decimals value is asserted + * by the caller. This may be useful when creating transactions offline or + * within a hardware wallet. * * Accounts expected by this instruction: * @@ -417,7 +435,8 @@ typedef struct Token_TokenInstruction_Token_InitializeMint_Body { typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { /** - * The number of signers (M) required to validate this multisignature account. + * The number of signers (M) required to validate this multisignature + * account. */ uint8_t m; } Token_TokenInstruction_Token_InitializeMultisig_Body; From d9c86ea5aebab8322faecaedb15138be9f089f5a Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Fri, 5 Feb 2021 18:54:18 -0700 Subject: [PATCH 111/335] token: cbindgen doing its thing... --- program/inc/token.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index e027ac5..7bedb8b 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -8,14 +8,14 @@ #include /** - * Maximum number of multisignature signers (max N) + * Minimum number of multisignature signers (min N) */ -#define Token_MAX_SIGNERS 11 +#define Token_MIN_SIGNERS 1 /** - * Minimum number of multisignature signers (min N) + * Maximum number of multisignature signers (max N) */ -#define Token_MIN_SIGNERS 1 +#define Token_MAX_SIGNERS 11 /** * Account state. @@ -263,9 +263,9 @@ typedef enum Token_TokenInstruction_Tag { * * * Multisignature owner/delegate * 0. `[writable]` The account to burn from. - * 1. '[writable]' The token mint. + * 1. `[writable]` The token mint. * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M '[signer]' M signer accounts. + * 3. ..3+M `[signer]` M signer accounts. */ Token_TokenInstruction_Burn, /** From 5af430263f0b4a5ec1176db07ac096db8d68e11c Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Fri, 5 Feb 2021 18:55:44 -0700 Subject: [PATCH 112/335] token: Get `COption` and `Pubkey` C bindings from solana-program crate --- program/inc/token.h | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index 7bedb8b..7cde65d 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -89,14 +89,12 @@ typedef enum Token_COption_Pubkey_Tag { Token_COption_Pubkey_Some_Pubkey, } Token_COption_Pubkey_Tag; -typedef struct Token_COption_Pubkey_Token_Some_Body_Pubkey { - Token_Pubkey _0; -} Token_COption_Pubkey_Token_Some_Body_Pubkey; - typedef struct Token_COption_Pubkey { Token_COption_Pubkey_Tag tag; union { - Token_COption_Pubkey_Token_Some_Body_Pubkey some; + struct { + Token_Pubkey some; + }; }; } Token_COption_Pubkey; @@ -430,7 +428,7 @@ typedef struct Token_TokenInstruction_Token_InitializeMint_Body { /** * The freeze authority/multisignature of the mint. */ - Token_COption_Pubkey freeze_authority; + struct Token_COption_Pubkey freeze_authority; } Token_TokenInstruction_Token_InitializeMint_Body; typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { @@ -463,7 +461,7 @@ typedef struct Token_TokenInstruction_Token_SetAuthority_Body { /** * The new authority */ - Token_COption_Pubkey new_authority; + struct Token_COption_Pubkey new_authority; } Token_TokenInstruction_Token_SetAuthority_Body; typedef struct Token_TokenInstruction_Token_MintTo_Body { @@ -550,7 +548,7 @@ typedef struct Token_Mint { * mint creation. If no mint authority is present then the mint has a fixed supply and no * further tokens may be minted. */ - Token_COption_Pubkey mint_authority; + struct Token_COption_Pubkey mint_authority; /** * Total supply of tokens. */ @@ -566,7 +564,7 @@ typedef struct Token_Mint { /** * Optional authority to freeze token accounts. */ - Token_COption_Pubkey freeze_authority; + struct Token_COption_Pubkey freeze_authority; } Token_Mint; /** @@ -583,14 +581,12 @@ typedef enum Token_COption_u64_Tag { Token_COption_u64_Some_u64, } Token_COption_u64_Tag; -typedef struct Token_COption_u64_Token_Some_Body_u64 { - uint64_t _0; -} Token_COption_u64_Token_Some_Body_u64; - typedef struct Token_COption_u64 { Token_COption_u64_Tag tag; union { - Token_COption_u64_Token_Some_Body_u64 some; + struct { + uint64_t some; + }; }; } Token_COption_u64; @@ -614,7 +610,7 @@ typedef struct Token_Account { * If `delegate` is `Some` then `delegated_amount` represents * the amount authorized by the delegate */ - Token_COption_Pubkey delegate; + struct Token_COption_Pubkey delegate; /** * The account's state */ @@ -624,7 +620,7 @@ typedef struct Token_Account { * is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped * SOL accounts do not drop below this threshold. */ - Token_COption_u64 is_native; + struct Token_COption_u64 is_native; /** * The amount delegated */ @@ -632,7 +628,7 @@ typedef struct Token_Account { /** * Optional authority to close the account. */ - Token_COption_Pubkey close_authority; + struct Token_COption_Pubkey close_authority; } Token_Account; /** From 91c14fa9a478c25e13c8dd2bea18b8d04934fdf0 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Fri, 5 Feb 2021 18:56:43 -0700 Subject: [PATCH 113/335] token: C binding comment typos --- program/inc/token.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index 7cde65d..c68a2eb 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -108,7 +108,7 @@ typedef enum Token_TokenInstruction_Tag { * * The `InitializeMint` instruction requires no signers and MUST be * included within the same Transaction as the system program's - * `CreateInstruction` that creates the account being initialized. + * `CreateAccount` instruction that creates the account being initialized. * Otherwise another party can acquire ownership of the uninitialized * account. * @@ -128,7 +128,7 @@ typedef enum Token_TokenInstruction_Tag { * * The `InitializeAccount` instruction requires no signers and MUST be * included within the same Transaction as the system program's - * `CreateInstruction` that creates the account being initialized. + * `CreateAccount` instruction that creates the account being initialized. * Otherwise another party can acquire ownership of the uninitialized * account. * @@ -150,7 +150,7 @@ typedef enum Token_TokenInstruction_Tag { * * The `InitializeMultisig` instruction requires no signers and MUST be * included within the same Transaction as the system program's - * `CreateInstruction` that creates the account being initialized. + * `CreateAccount` instruction that creates the account being initialized. * Otherwise another party can acquire ownership of the uninitialized * account. * @@ -226,7 +226,7 @@ typedef enum Token_TokenInstruction_Tag { * * * Multisignature authority * 0. `[writable]` The mint or account to change the authority of. - * 1. `[]` The mint's or account's multisignature authority. + * 1. `[]` The mint's or account's current multisignature authority. * 2. ..2+M `[signer]` M signer accounts */ Token_TokenInstruction_SetAuthority, From 7f1dfacadee5d7ab2683d745a415126c25720654 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Fri, 5 Feb 2021 18:58:05 -0700 Subject: [PATCH 114/335] token: Rename v2 instructions in C bindings --- program/inc/token.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/program/inc/token.h b/program/inc/token.h index c68a2eb..726032a 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -326,7 +326,7 @@ typedef enum Token_TokenInstruction_Tag { * account. * * This instruction differs from Transfer in that the token mint and - * decimals value is asserted by the caller. This may be useful when + * decimals value is checked by the caller. This may be useful when * creating transactions offline or within a hardware wallet. * * Accounts expected by this instruction: @@ -344,13 +344,13 @@ typedef enum Token_TokenInstruction_Tag { * 3. `[]` The source account's multisignature owner/delegate. * 4. ..4+M `[signer]` M signer accounts. */ - Token_TokenInstruction_Transfer2, + Token_TokenInstruction_TransferChecked, /** * Approves a delegate. A delegate is given the authority over tokens on * behalf of the source account's owner. * * This instruction differs from Approve in that the token mint and - * decimals value is asserted by the caller. This may be useful when + * decimals value is checked by the caller. This may be useful when * creating transactions offline or within a hardware wallet. * * Accounts expected by this instruction: @@ -368,13 +368,13 @@ typedef enum Token_TokenInstruction_Tag { * 3. `[]` The source account's multisignature owner. * 4. ..4+M `[signer]` M signer accounts */ - Token_TokenInstruction_Approve2, + Token_TokenInstruction_ApproveChecked, /** * Mints new tokens to an account. The native mint does not support * minting. * * This instruction differs from MintTo in that the decimals value is - * asserted by the caller. This may be useful when creating transactions + * checked by the caller. This may be useful when creating transactions * offline or within a hardware wallet. * * Accounts expected by this instruction: @@ -390,13 +390,13 @@ typedef enum Token_TokenInstruction_Tag { * 2. `[]` The mint's multisignature mint-tokens authority. * 3. ..3+M `[signer]` M signer accounts. */ - Token_TokenInstruction_MintTo2, + Token_TokenInstruction_MintToChecked, /** - * Burns tokens by removing them from an account. `Burn2` does not + * Burns tokens by removing them from an account. `BurnChecked` does not * support accounts associated with the native mint, use `CloseAccount` * instead. * - * This instruction differs from Burn in that the decimals value is asserted + * This instruction differs from Burn in that the decimals value is checked * by the caller. This may be useful when creating transactions offline or * within a hardware wallet. * @@ -413,7 +413,7 @@ typedef enum Token_TokenInstruction_Tag { * 2. `[]` The account's multisignature owner/delegate. * 3. ..3+M `[signer]` M signer accounts. */ - Token_TokenInstruction_Burn2, + Token_TokenInstruction_BurnChecked, } Token_TokenInstruction_Tag; typedef struct Token_TokenInstruction_Token_InitializeMint_Body { @@ -478,7 +478,7 @@ typedef struct Token_TokenInstruction_Token_Burn_Body { uint64_t amount; } Token_TokenInstruction_Token_Burn_Body; -typedef struct Token_TokenInstruction_Token_Transfer2_Body { +typedef struct Token_TokenInstruction_Token_TransferChecked_Body { /** * The amount of tokens to transfer. */ @@ -487,9 +487,9 @@ typedef struct Token_TokenInstruction_Token_Transfer2_Body { * Expected number of base 10 digits to the right of the decimal place. */ uint8_t decimals; -} Token_TokenInstruction_Token_Transfer2_Body; +} Token_TokenInstruction_Token_TransferChecked_Body; -typedef struct Token_TokenInstruction_Token_Approve2_Body { +typedef struct Token_TokenInstruction_Token_ApproveChecked_Body { /** * The amount of tokens the delegate is approved for. */ @@ -498,9 +498,9 @@ typedef struct Token_TokenInstruction_Token_Approve2_Body { * Expected number of base 10 digits to the right of the decimal place. */ uint8_t decimals; -} Token_TokenInstruction_Token_Approve2_Body; +} Token_TokenInstruction_Token_ApproveChecked_Body; -typedef struct Token_TokenInstruction_Token_MintTo2_Body { +typedef struct Token_TokenInstruction_Token_MintToChecked_Body { /** * The amount of new tokens to mint. */ @@ -509,9 +509,9 @@ typedef struct Token_TokenInstruction_Token_MintTo2_Body { * Expected number of base 10 digits to the right of the decimal place. */ uint8_t decimals; -} Token_TokenInstruction_Token_MintTo2_Body; +} Token_TokenInstruction_Token_MintToChecked_Body; -typedef struct Token_TokenInstruction_Token_Burn2_Body { +typedef struct Token_TokenInstruction_Token_BurnChecked_Body { /** * The amount of tokens to burn. */ @@ -520,7 +520,7 @@ typedef struct Token_TokenInstruction_Token_Burn2_Body { * Expected number of base 10 digits to the right of the decimal place. */ uint8_t decimals; -} Token_TokenInstruction_Token_Burn2_Body; +} Token_TokenInstruction_Token_BurnChecked_Body; typedef struct Token_TokenInstruction { Token_TokenInstruction_Tag tag; @@ -532,10 +532,10 @@ typedef struct Token_TokenInstruction { Token_TokenInstruction_Token_SetAuthority_Body set_authority; Token_TokenInstruction_Token_MintTo_Body mint_to; Token_TokenInstruction_Token_Burn_Body burn; - Token_TokenInstruction_Token_Transfer2_Body transfer2; - Token_TokenInstruction_Token_Approve2_Body approve2; - Token_TokenInstruction_Token_MintTo2_Body mint_to2; - Token_TokenInstruction_Token_Burn2_Body burn2; + Token_TokenInstruction_Token_TransferChecked_Body transfer_checked; + Token_TokenInstruction_Token_ApproveChecked_Body approve_checked; + Token_TokenInstruction_Token_MintToChecked_Body mint_to_checked; + Token_TokenInstruction_Token_BurnChecked_Body burn_checked; }; } Token_TokenInstruction; From 0a9079fb38ff1ec7af6209a1b7f85c00e6c52b66 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Fri, 5 Feb 2021 18:58:44 -0700 Subject: [PATCH 115/335] token: Add `InitializeAccount2` C binding --- program/inc/token.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/program/inc/token.h b/program/inc/token.h index 726032a..f68bba7 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -414,6 +414,19 @@ typedef enum Token_TokenInstruction_Tag { * 3. ..3+M `[signer]` M signer accounts. */ Token_TokenInstruction_BurnChecked, + /** + * Like InitializeAccount, but the owner pubkey is passed via instruction data + * rather than the accounts list. This variant may be preferable when using + * Cross Program Invocation from an instruction that does not need the owner's + * `AccountInfo` otherwise. + * + * Accounts expected by this instruction: + * + * 0. `[writable]` The account to initialize. + * 1. `[]` The mint this account will be associated with. + * 3. `[]` Rent sysvar + */ + Token_TokenInstruction_InitializeAccount2, } Token_TokenInstruction_Tag; typedef struct Token_TokenInstruction_Token_InitializeMint_Body { @@ -522,6 +535,13 @@ typedef struct Token_TokenInstruction_Token_BurnChecked_Body { uint8_t decimals; } Token_TokenInstruction_Token_BurnChecked_Body; +typedef struct Token_TokenInstruction_Token_InitializeAccount2_Body { + /** + * The new account's owner/multisignature. + */ + Token_Pubkey owner; +} Token_TokenInstruction_Token_InitializeAccount2_Body; + typedef struct Token_TokenInstruction { Token_TokenInstruction_Tag tag; union { @@ -536,6 +556,7 @@ typedef struct Token_TokenInstruction { Token_TokenInstruction_Token_ApproveChecked_Body approve_checked; Token_TokenInstruction_Token_MintToChecked_Body mint_to_checked; Token_TokenInstruction_Token_BurnChecked_Body burn_checked; + Token_TokenInstruction_Token_InitializeAccount2_Body initialize_account2; }; } Token_TokenInstruction; From 9f001628678b9727808681e6017b886464705021 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Thu, 11 Feb 2021 14:18:38 -0700 Subject: [PATCH 116/335] chore: bump solana crates to 1.5.6 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 8c66334..2472390 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.5.1" +solana-program = "1.5.6" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.5.0" +solana-sdk = "1.5.6" [lib] crate-type = ["cdylib", "lib"] From 6144927d090fa9e495afa3b268896c843159f8cf Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Thu, 11 Feb 2021 14:28:05 -0700 Subject: [PATCH 117/335] chore: token - bump version to 3.1.0 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 2472390..fa7162b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.0.1" +version = "3.1.0" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 1165d53bb774a3733fb0700f02baef7dcfe1411b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Feb 2021 23:56:18 +0000 Subject: [PATCH 118/335] build(deps): bump solana-program from 1.5.6 to 1.5.8 (#1261) Bumps [solana-program](https://github.com/solana-labs/solana) from 1.5.6 to 1.5.8. - [Release notes](https://github.com/solana-labs/solana/releases) - [Changelog](https://github.com/solana-labs/solana/blob/master/RELEASE.md) - [Commits](https://github.com/solana-labs/solana/compare/v1.5.6...v1.5.8) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index fa7162b..da8e8c3 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,7 +16,7 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.5.6" +solana-program = "1.5.8" thiserror = "1.0" [dev-dependencies] From 3bc89d703ae0a58885926a34f760f1311eee39a8 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 2 Mar 2021 19:19:50 +0100 Subject: [PATCH 119/335] Update solana-program to 1.5.11 (#1362) * Update solana-program to 1.5.11 * Update all programs --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index da8e8c3..480394d 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.5.8" +solana-program = "1.5.11" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.5.6" +solana-sdk = "1.5.11" [lib] crate-type = ["cdylib", "lib"] From 6414320d84ca23cb2c7e75b97a1092e8d6f7d432 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Tue, 16 Mar 2021 13:47:59 -0700 Subject: [PATCH 120/335] Bump Solana version to 1.5.15 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 480394d..af666c6 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.5.11" +solana-program = "1.5.15" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.5.11" +solana-sdk = "1.5.15" [lib] crate-type = ["cdylib", "lib"] From 16410bc543a7e10e8a856009d14d0e8cf800857d Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 15 Mar 2021 22:35:48 -0700 Subject: [PATCH 121/335] Bump Rust version to 1.50.0 --- program/src/processor.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/program/src/processor.rs b/program/src/processor.rs index 5d22ca5..ea9fb7f 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -159,6 +159,7 @@ impl Processor { let source_account_info = next_account_info(account_info_iter)?; + #[allow(clippy::manual_map)] let expected_mint_info = if let Some(expected_decimals) = expected_decimals { Some((next_account_info(account_info_iter)?, expected_decimals)) } else { @@ -266,6 +267,8 @@ impl Processor { let account_info_iter = &mut accounts.iter(); let source_account_info = next_account_info(account_info_iter)?; + + #[allow(clippy::manual_map)] let expected_mint_info = if let Some(expected_decimals) = expected_decimals { Some((next_account_info(account_info_iter)?, expected_decimals)) } else { From d9859e93f3ae55e9c5031b1c331b514073fdaaca Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Tue, 16 Mar 2021 20:31:22 -0700 Subject: [PATCH 122/335] Back out clippy::manual_map for now --- program/src/processor.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index ea9fb7f..7171741 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -159,7 +159,6 @@ impl Processor { let source_account_info = next_account_info(account_info_iter)?; - #[allow(clippy::manual_map)] let expected_mint_info = if let Some(expected_decimals) = expected_decimals { Some((next_account_info(account_info_iter)?, expected_decimals)) } else { @@ -268,7 +267,6 @@ impl Processor { let source_account_info = next_account_info(account_info_iter)?; - #[allow(clippy::manual_map)] let expected_mint_info = if let Some(expected_decimals) = expected_decimals { Some((next_account_info(account_info_iter)?, expected_decimals)) } else { From 956ada780405cc71fc6e6c89fd355a708d9c2192 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 17 Mar 2021 20:21:21 -0700 Subject: [PATCH 123/335] Bump Solana version to 1.6.1 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index af666c6..7da140b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.5.15" +solana-program = "1.6.1" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.5.15" +solana-sdk = "1.6.1" [lib] crate-type = ["cdylib", "lib"] From f07cfe6e3a90795e85ecd9db372c2fe3bc4e1ef1 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Tue, 30 Mar 2021 08:41:53 -0700 Subject: [PATCH 124/335] Update to Solana 1.6.2 --- program/Cargo.toml | 4 ++-- program/src/processor.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 7da140b..7c6480b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.6.1" +solana-program = "1.6.2" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.6.1" +solana-sdk = "1.6.2" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/src/processor.rs b/program/src/processor.rs index 7171741..b4080be 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -811,7 +811,7 @@ mod tests { account_info::IntoAccountInfo, clock::Epoch, instruction::Instruction, sysvar::rent, }; use solana_sdk::account::{ - create_account, create_is_signer_account_infos, Account as SolanaAccount, + create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, }; fn do_process_instruction( @@ -841,7 +841,7 @@ mod tests { } fn rent_sysvar() -> SolanaAccount { - create_account(&Rent::default(), 42) + create_account_for_test(&Rent::default()) } fn mint_minimum_balance() -> u64 { From e72aa91b144c761b9cee662a691f48afd28503b2 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 23 Apr 2021 12:31:36 -0700 Subject: [PATCH 125/335] Update SPL to Solana v1.6.6 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 7c6480b..14c8749 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.6.2" +solana-program = "1.6.6" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.6.2" +solana-sdk = "1.6.6" [lib] crate-type = ["cdylib", "lib"] From 586f6a8477a78f7efe222565fef5a6870f5d6406 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Tue, 4 May 2021 22:03:15 -0600 Subject: [PATCH 126/335] Bump solana crates to v1.6.7 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 14c8749..3809761 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.6.6" +solana-program = "1.6.7" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.6.6" +solana-sdk = "1.6.7" [lib] crate-type = ["cdylib", "lib"] From 38751ab1fd22c8cf6e9e14575905242753cf591a Mon Sep 17 00:00:00 2001 From: Elliott Benisty Date: Wed, 12 May 2021 23:36:41 +0100 Subject: [PATCH 127/335] Fix potential vulnerabilities in programs using spl-token CPIs by adding program id checks (#1714) * Add spl-token program id check helper function. Add program id to instruction bindings. * Run cargo fmt * Fixup tests * Skip ATA tests when custom token program-id Co-authored-by: Tyera Eulberg --- program/src/instruction.rs | 19 ++++++++++++++- program/src/lib.rs | 9 +++++++ program/src/processor.rs | 48 +++++++++++++++++++------------------- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 063eb7c..da28205 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -1,6 +1,6 @@ //! Instruction types -use crate::error::TokenError; +use crate::{check_program_account, error::TokenError}; use solana_program::{ instruction::{AccountMeta, Instruction}, program_error::ProgramError, @@ -620,6 +620,7 @@ pub fn initialize_mint( freeze_authority_pubkey: Option<&Pubkey>, decimals: u8, ) -> Result { + check_program_account(token_program_id)?; let freeze_authority = freeze_authority_pubkey.cloned().into(); let data = TokenInstruction::InitializeMint { mint_authority: *mint_authority_pubkey, @@ -647,6 +648,7 @@ pub fn initialize_account( mint_pubkey: &Pubkey, owner_pubkey: &Pubkey, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::InitializeAccount.pack(); let accounts = vec![ @@ -670,6 +672,7 @@ pub fn initialize_account2( mint_pubkey: &Pubkey, owner_pubkey: &Pubkey, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::InitializeAccount2 { owner: *owner_pubkey, } @@ -695,6 +698,7 @@ pub fn initialize_multisig( signer_pubkeys: &[&Pubkey], m: u8, ) -> Result { + check_program_account(token_program_id)?; if !is_valid_signer_index(m as usize) || !is_valid_signer_index(signer_pubkeys.len()) || m as usize > signer_pubkeys.len() @@ -726,6 +730,7 @@ pub fn transfer( signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::Transfer { amount }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); @@ -755,6 +760,7 @@ pub fn approve( signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::Approve { amount }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); @@ -782,6 +788,7 @@ pub fn revoke( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::Revoke.pack(); let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len()); @@ -810,6 +817,7 @@ pub fn set_authority( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { + check_program_account(token_program_id)?; let new_authority = new_authority_pubkey.cloned().into(); let data = TokenInstruction::SetAuthority { authority_type, @@ -843,6 +851,7 @@ pub fn mint_to( signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::MintTo { amount }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); @@ -872,6 +881,7 @@ pub fn burn( signer_pubkeys: &[&Pubkey], amount: u64, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::Burn { amount }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); @@ -900,6 +910,7 @@ pub fn close_account( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::CloseAccount.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); @@ -928,6 +939,7 @@ pub fn freeze_account( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::FreezeAccount.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); @@ -956,6 +968,7 @@ pub fn thaw_account( owner_pubkey: &Pubkey, signer_pubkeys: &[&Pubkey], ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::ThawAccount.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); @@ -988,6 +1001,7 @@ pub fn transfer_checked( amount: u64, decimals: u8, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::TransferChecked { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); @@ -1021,6 +1035,7 @@ pub fn approve_checked( amount: u64, decimals: u8, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::ApproveChecked { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len()); @@ -1052,6 +1067,7 @@ pub fn mint_to_checked( amount: u64, decimals: u8, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::MintToChecked { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); @@ -1082,6 +1098,7 @@ pub fn burn_checked( amount: u64, decimals: u8, ) -> Result { + check_program_account(token_program_id)?; let data = TokenInstruction::BurnChecked { amount, decimals }.pack(); let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len()); diff --git a/program/src/lib.rs b/program/src/lib.rs index a561e30..529aaa1 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -14,6 +14,7 @@ mod entrypoint; // Export current sdk types for downstream users building with a different sdk version pub use solana_program; +use solana_program::{entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey}; /// Convert the UI representation of a token amount (using the decimals field defined in its mint) /// to the raw amount @@ -27,3 +28,11 @@ pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { } solana_program::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); + +/// Checks that the supplied program ID is the correct one for SPL-token +pub fn check_program_account(spl_token_program_id: &Pubkey) -> ProgramResult { + if spl_token_program_id != &id() { + return Err(ProgramError::IncorrectProgramId); + } + Ok(()) +} diff --git a/program/src/processor.rs b/program/src/processor.rs index b4080be..4ba5bcc 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -985,7 +985,7 @@ mod tests { #[test] fn test_initialize_mint() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let owner_key = Pubkey::new_unique(); let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); @@ -1033,7 +1033,7 @@ mod tests { #[test] fn test_initialize_mint_account() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); let owner_key = Pubkey::new_unique(); @@ -1109,7 +1109,7 @@ mod tests { #[test] fn test_transfer_dups() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), @@ -1416,7 +1416,7 @@ mod tests { #[test] fn test_transfer() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -1837,7 +1837,7 @@ mod tests { #[test] fn test_self_transfer() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -2367,7 +2367,7 @@ mod tests { #[test] fn test_mintable_token_with_zero_supply() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -2466,7 +2466,7 @@ mod tests { #[test] fn test_approve_dups() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), @@ -2677,7 +2677,7 @@ mod tests { #[test] fn test_approve() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -2882,7 +2882,7 @@ mod tests { #[test] fn test_set_authority_dups() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), @@ -2985,7 +2985,7 @@ mod tests { #[test] fn test_set_authority() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -3324,7 +3324,7 @@ mod tests { #[test] fn test_mint_to_dups() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), @@ -3420,7 +3420,7 @@ mod tests { #[test] fn test_mint_to() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -3623,7 +3623,7 @@ mod tests { #[test] fn test_burn_dups() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), @@ -3823,7 +3823,7 @@ mod tests { #[test] fn test_burn() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -4088,7 +4088,7 @@ mod tests { #[test] fn test_multisig() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); @@ -4492,7 +4492,7 @@ mod tests { #[test] fn test_validate_owner() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let owner_key = Pubkey::new_unique(); let mut signer_keys = [Pubkey::default(); MAX_SIGNERS]; for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) { @@ -4652,7 +4652,7 @@ mod tests { #[test] fn test_close_account_dups() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), @@ -4738,7 +4738,7 @@ mod tests { #[test] fn test_close_account() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); @@ -4967,7 +4967,7 @@ mod tests { #[test] fn test_native_token() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); let account_key = Pubkey::new_unique(); @@ -5144,7 +5144,7 @@ mod tests { #[test] fn test_overflow() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -5321,7 +5321,7 @@ mod tests { #[test] fn test_frozen() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -5507,7 +5507,7 @@ mod tests { #[test] fn test_freeze_thaw_dups() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account1_key = Pubkey::new_unique(); let mut account1_account = SolanaAccount::new( account_minimum_balance(), @@ -5571,7 +5571,7 @@ mod tests { #[test] fn test_freeze_account() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), @@ -5684,7 +5684,7 @@ mod tests { #[test] fn test_initialize_account2() { - let program_id = Pubkey::new_unique(); + let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( account_minimum_balance(), From 7e95bf7da776b5733355108618176339d5d9b836 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 17 May 2021 20:26:25 -0700 Subject: [PATCH 128/335] Bump spl-token patch version --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 3809761..b963355 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.1.0" +version = "3.1.1" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 6fba2a317d2c7602e5d808f9c118d0fc46c5fcd9 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Wed, 19 May 2021 00:32:12 +0800 Subject: [PATCH 129/335] Fix #1739: ThawAccount incorrectly logged as FreezeAccount in token program (#1740) --- program/src/processor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 4ba5bcc..48d09a6 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -702,7 +702,7 @@ impl Processor { Self::process_toggle_freeze_account(program_id, accounts, true) } TokenInstruction::ThawAccount => { - msg!("Instruction: FreezeAccount"); + msg!("Instruction: ThawAccount"); Self::process_toggle_freeze_account(program_id, accounts, false) } TokenInstruction::TransferChecked { amount, decimals } => { From 6d544040da8d1711df8def8fb567cd225ced77f8 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 14 Jun 2021 14:44:58 -0600 Subject: [PATCH 130/335] Bump solana version --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index b963355..dd657a5 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.6.7" +solana-program = "1.6.11" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.6.7" +solana-sdk = "1.6.11" [lib] crate-type = ["cdylib", "lib"] From 94107a4bbefd067adb0f5958fb978f78db882a5a Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 25 Jun 2021 00:39:08 +0200 Subject: [PATCH 131/335] Update all solana dependencies to 1.7.3, fix issues (#1958) * Update all dependencies to 1.7.3, fix issues * Remove esm from mocha * Fix missed token test * Also update rust version * token-swap: update tolerance on sim test * Run `cargo clippy --fix` for needless_borrow errors * Rerun cargo fmt --- program/Cargo.toml | 4 +- program/src/processor.rs | 120 +++++++++++++++++++-------------------- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index dd657a5..8dea41a 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.6.11" +solana-program = "1.7.3" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.6.11" +solana-sdk = "1.7.3" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/src/processor.rs b/program/src/processor.rs index 48d09a6..d91f618 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1927,9 +1927,9 @@ mod tests { // transfer let instruction = transfer( &program_id, - &account_info.key, - &account_info.key, - &owner_info.key, + account_info.key, + account_info.key, + owner_info.key, &[], 1000, ) @@ -1953,10 +1953,10 @@ mod tests { // transfer checked let instruction = transfer_checked( &program_id, - &account_info.key, - &mint_info.key, - &account_info.key, - &owner_info.key, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, &[], 1000, 2, @@ -1983,9 +1983,9 @@ mod tests { let mut owner_no_sign_info = owner_info.clone(); let mut instruction = transfer( &program_id, - &account_info.key, - &account_info.key, - &owner_no_sign_info.key, + account_info.key, + account_info.key, + owner_no_sign_info.key, &[], 1000, ) @@ -2008,10 +2008,10 @@ mod tests { // missing signer checked let mut instruction = transfer_checked( &program_id, - &account_info.key, - &mint_info.key, - &account_info.key, - &owner_no_sign_info.key, + account_info.key, + mint_info.key, + account_info.key, + owner_no_sign_info.key, &[], 1000, 2, @@ -2035,9 +2035,9 @@ mod tests { // missing owner let instruction = transfer( &program_id, - &account_info.key, - &account_info.key, - &owner2_info.key, + account_info.key, + account_info.key, + owner2_info.key, &[], 1000, ) @@ -2058,10 +2058,10 @@ mod tests { // missing owner checked let instruction = transfer_checked( &program_id, - &account_info.key, - &mint_info.key, - &account_info.key, - &owner2_info.key, + account_info.key, + mint_info.key, + account_info.key, + owner2_info.key, &[], 1000, 2, @@ -2084,9 +2084,9 @@ mod tests { // insufficient funds let instruction = transfer( &program_id, - &account_info.key, - &account_info.key, - &owner_info.key, + account_info.key, + account_info.key, + owner_info.key, &[], 1001, ) @@ -2107,10 +2107,10 @@ mod tests { // insufficient funds checked let instruction = transfer_checked( &program_id, - &account_info.key, - &mint_info.key, - &account_info.key, - &owner_info.key, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, &[], 1001, 2, @@ -2133,10 +2133,10 @@ mod tests { // incorrect decimals let instruction = transfer_checked( &program_id, - &account_info.key, - &mint_info.key, - &account_info.key, - &owner_info.key, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, &[], 1, 10, // <-- incorrect decimals @@ -2159,10 +2159,10 @@ mod tests { // incorrect mint let instruction = transfer_checked( &program_id, - &account_info.key, - &account3_info.key, // <-- incorrect mint - &account_info.key, - &owner_info.key, + account_info.key, + account3_info.key, // <-- incorrect mint + account_info.key, + owner_info.key, &[], 1, 2, @@ -2185,9 +2185,9 @@ mod tests { // approve delegate let instruction = approve( &program_id, - &account_info.key, - &delegate_info.key, - &owner_info.key, + account_info.key, + delegate_info.key, + owner_info.key, &[], 100, ) @@ -2206,9 +2206,9 @@ mod tests { // delegate transfer let instruction = transfer( &program_id, - &account_info.key, - &account_info.key, - &delegate_info.key, + account_info.key, + account_info.key, + delegate_info.key, &[], 100, ) @@ -2233,10 +2233,10 @@ mod tests { // delegate transfer checked let instruction = transfer_checked( &program_id, - &account_info.key, - &mint_info.key, - &account_info.key, - &delegate_info.key, + account_info.key, + mint_info.key, + account_info.key, + delegate_info.key, &[], 100, 2, @@ -2263,9 +2263,9 @@ mod tests { // delegate insufficient funds let instruction = transfer( &program_id, - &account_info.key, - &account_info.key, - &delegate_info.key, + account_info.key, + account_info.key, + delegate_info.key, &[], 101, ) @@ -2286,10 +2286,10 @@ mod tests { // delegate insufficient funds checked let instruction = transfer_checked( &program_id, - &account_info.key, - &mint_info.key, - &account_info.key, - &delegate_info.key, + account_info.key, + mint_info.key, + account_info.key, + delegate_info.key, &[], 101, 2, @@ -2312,9 +2312,9 @@ mod tests { // owner transfer with delegate assigned let instruction = transfer( &program_id, - &account_info.key, - &account_info.key, - &owner_info.key, + account_info.key, + account_info.key, + owner_info.key, &[], 1000, ) @@ -2338,10 +2338,10 @@ mod tests { // owner transfer with delegate assigned checked let instruction = transfer_checked( &program_id, - &account_info.key, - &mint_info.key, - &account_info.key, - &owner_info.key, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, &[], 1000, 2, From 01e550502679dd484298d5e6183c0ddfee102608 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 2 Jul 2021 10:53:41 -0600 Subject: [PATCH 132/335] Bump solana and borsh crates (#2015) --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 8dea41a..74b77da 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.1" -solana-program = "1.7.3" +solana-program = "1.7.4" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.7.3" +solana-sdk = "1.7.4" [lib] crate-type = ["cdylib", "lib"] From 9244fa91242b5f6893335717be6fd528680fa99d Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Thu, 15 Jul 2021 11:56:15 +0200 Subject: [PATCH 133/335] token: Drop delegate on ownership transfer (#2085) * token: Drop delegate on ownership transfer * Unconditionalize the block --- program/src/processor.rs | 48 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index d91f618..3338556 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -367,6 +367,9 @@ impl Processor { } else { return Err(TokenError::InvalidInstruction.into()); } + + account.delegate = COption::None; + account.delegated_amount = 0; } AuthorityType::CloseAccount => { let authority = account.close_authority.unwrap_or(account.owner); @@ -3003,6 +3006,7 @@ mod tests { let owner2_key = Pubkey::new_unique(); let mut owner2_account = SolanaAccount::default(); let owner3_key = Pubkey::new_unique(); + let mut owner3_account = SolanaAccount::default(); let mint_key = Pubkey::new_unique(); let mut mint_account = SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); @@ -3133,12 +3137,34 @@ mod tests { ) ); + // set delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &owner2_key, + &owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut account_account, + &mut owner2_account, + &mut owner_account, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.delegate, COption::Some(owner2_key)); + assert_eq!(account.delegated_amount, u64::MAX); + // set owner do_process_instruction( set_authority( &program_id, &account_key, - Some(&owner2_key), + Some(&owner3_key), AuthorityType::AccountOwner, &owner_key, &[], @@ -3148,6 +3174,26 @@ mod tests { ) .unwrap(); + // check delegate cleared + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.delegate, COption::None); + assert_eq!(account.delegated_amount, 0); + + // set owner without existing delegate + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner3_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner3_account], + ) + .unwrap(); + // set close_authority do_process_instruction( set_authority( From 3f321e536d0de762b39db39aae26dd4d02292090 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Mon, 19 Jul 2021 21:50:42 +0200 Subject: [PATCH 134/335] token: Add SyncNative instruction (program, CLI, JS) (#2091) * Add SyncNative to program * Add CLI support * Add JS bindings * Fix syncNative test to not run for existing token program * Combine checks --- program/src/error.rs | 10 +++ program/src/instruction.rs | 35 +++++++++ program/src/processor.rs | 156 +++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) diff --git a/program/src/error.rs b/program/src/error.rs index 8305eaa..ed3faed 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -7,6 +7,7 @@ use thiserror::Error; /// Errors that may be returned by the Token program. #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] pub enum TokenError { + // 0 /// Lamport balance below rent-exempt threshold. #[error("Lamport balance below rent-exempt threshold")] NotRentExempt, @@ -22,6 +23,8 @@ pub enum TokenError { /// Owner does not match. #[error("Owner does not match")] OwnerMismatch, + + // 5 /// This token's supply is fixed and new tokens cannot be minted. #[error("Fixed supply")] FixedSupply, @@ -37,6 +40,8 @@ pub enum TokenError { /// State is uninitialized. #[error("State is unititialized")] UninitializedState, + + // 10 /// Instruction does not support native tokens #[error("Instruction does not support native tokens")] NativeNotSupported, @@ -52,6 +57,8 @@ pub enum TokenError { /// Operation overflowed #[error("Operation overflowed")] Overflow, + + // 15 /// Account does not support specified authority type. #[error("Account does not support specified authority type")] AuthorityTypeNotSupported, @@ -64,6 +71,9 @@ pub enum TokenError { /// Mint decimals mismatch between the client and mint #[error("The provided decimals value different from the Mint decimals")] MintDecimalsMismatch, + /// Instruction does not support non-native tokens + #[error("Instruction does not support non-native tokens")] + NonNativeNotSupported, } impl From for ProgramError { fn from(e: TokenError) -> Self { diff --git a/program/src/instruction.rs b/program/src/instruction.rs index da28205..3e9629a 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -363,6 +363,16 @@ pub enum TokenInstruction { /// The new account's owner/multisignature. owner: Pubkey, }, + /// Given a wrapped / native token account (a token account containing SOL) + /// updates its amount field based on the account's underlying `lamports`. + /// This is useful if a non-wrapped SOL account uses `system_instruction::transfer` + /// to move lamports to a wrapped token account, and needs to have its token + /// `amount` field updated. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The native token account to sync with its underlying lamports. + SyncNative, } impl TokenInstruction { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). @@ -464,6 +474,7 @@ impl TokenInstruction { let (owner, _rest) = Self::unpack_pubkey(rest)?; Self::InitializeAccount2 { owner } } + 17 => Self::SyncNative, _ => return Err(TokenError::InvalidInstruction.into()), }) @@ -540,6 +551,9 @@ impl TokenInstruction { buf.push(16); buf.extend_from_slice(owner.as_ref()); } + &Self::SyncNative => { + buf.push(17); + } }; buf } @@ -1119,6 +1133,20 @@ pub fn burn_checked( }) } +/// Creates a `SyncNative` instruction +pub fn sync_native( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, +) -> Result { + check_program_account(token_program_id)?; + + Ok(Instruction { + program_id: *token_program_id, + accounts: vec![AccountMeta::new(*account_pubkey, false)], + data: TokenInstruction::SyncNative.pack(), + }) +} + /// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS pub fn is_valid_signer_index(index: usize) -> bool { (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) @@ -1288,5 +1316,12 @@ mod test { assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); + + let check = TokenInstruction::SyncNative; + let packed = check.pack(); + let expect = vec![17u8]; + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); } } diff --git a/program/src/processor.rs b/program/src/processor.rs index 3338556..44f66f4 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -644,6 +644,33 @@ impl Processor { Ok(()) } + /// Processes a [SyncNative](enum.TokenInstruction.html) instruction + pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let native_account_info = next_account_info(account_info_iter)?; + + if native_account_info.owner != program_id { + return Err(ProgramError::IncorrectProgramId); + } + let mut native_account = Account::unpack(&native_account_info.data.borrow())?; + + if let COption::Some(rent_exempt_reserve) = native_account.is_native { + let new_amount = native_account_info + .lamports() + .checked_sub(rent_exempt_reserve) + .ok_or(TokenError::Overflow)?; + if new_amount < native_account.amount { + return Err(TokenError::InvalidState.into()); + } + native_account.amount = new_amount; + } else { + return Err(TokenError::NonNativeNotSupported.into()); + } + + Account::pack(native_account, &mut native_account_info.data.borrow_mut())?; + Ok(()) + } + /// Processes an [Instruction](enum.Instruction.html). pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { let instruction = TokenInstruction::unpack(input)?; @@ -724,6 +751,10 @@ impl Processor { msg!("Instruction: BurnChecked"); Self::process_burn(program_id, accounts, amount, Some(decimals)) } + TokenInstruction::SyncNative => { + msg!("Instruction: SyncNative"); + Self::process_sync_native(program_id, accounts) + } } } @@ -802,6 +833,9 @@ impl PrintProgramError for TokenError { TokenError::MintDecimalsMismatch => { msg!("Error: decimals different from the Mint decimals") } + TokenError::NonNativeNotSupported => { + msg!("Error: Instruction does not support non-native tokens") + } } } } @@ -5775,4 +5809,126 @@ mod tests { assert_eq!(account_account, account2_account); } + + #[test] + fn test_sync_native() { + let program_id = crate::id(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let native_account_key = Pubkey::new_unique(); + let lamports = 40; + let mut native_account = SolanaAccount::new( + account_minimum_balance() + lamports, + Account::get_packed_len(), + &program_id, + ); + let non_native_account_key = Pubkey::new_unique(); + let mut non_native_account = SolanaAccount::new( + account_minimum_balance() + 50, + Account::get_packed_len(), + &program_id, + ); + + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mut rent_sysvar = rent_sysvar(); + + // initialize non-native mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // initialize non-native account + do_process_instruction( + initialize_account(&program_id, &non_native_account_key, &mint_key, &owner_key) + .unwrap(), + vec![ + &mut non_native_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + let account = Account::unpack_unchecked(&non_native_account.data).unwrap(); + assert!(!account.is_native()); + assert_eq!(account.amount, 0); + + // fail sync non-native + assert_eq!( + Err(TokenError::NonNativeNotSupported.into()), + do_process_instruction( + sync_native(&program_id, &non_native_account_key,).unwrap(), + vec![&mut non_native_account], + ) + ); + + // fail sync uninitialized + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + sync_native(&program_id, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); + + // wrap native account + do_process_instruction( + initialize_account( + &program_id, + &native_account_key, + &crate::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut native_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, lamports); + + // sync, no change + do_process_instruction( + sync_native(&program_id, &native_account_key).unwrap(), + vec![&mut native_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert_eq!(account.amount, lamports); + + // transfer sol + let new_lamports = lamports + 50; + native_account.lamports = account_minimum_balance() + new_lamports; + + // success sync + do_process_instruction( + sync_native(&program_id, &native_account_key).unwrap(), + vec![&mut native_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert_eq!(account.amount, new_lamports); + + // reduce sol + native_account.lamports -= 1; + + // fail sync + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + sync_native(&program_id, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); + } } From 164d6e3fd39721d29851c32c16911520a056d0ae Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 19 Jul 2021 17:57:26 -0600 Subject: [PATCH 135/335] token: Bump C bindings (#2109) * Update token C bindings * Fix Readme typo --- program/inc/token.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/program/inc/token.h b/program/inc/token.h index f68bba7..145c0c5 100644 --- a/program/inc/token.h +++ b/program/inc/token.h @@ -427,6 +427,18 @@ typedef enum Token_TokenInstruction_Tag { * 3. `[]` Rent sysvar */ Token_TokenInstruction_InitializeAccount2, + /** + * Given a wrapped / native token account (a token account containing SOL) + * updates its amount field based on the account's underlying `lamports`. + * This is useful if a non-wrapped SOL account uses `system_instruction::transfer` + * to move lamports to a wrapped token account, and needs to have its token + * `amount` field updated. + * + * Accounts expected by this instruction: + * + * 0. `[writable]` The native token account to sync with its underlying lamports. + */ + Token_TokenInstruction_SyncNative, } Token_TokenInstruction_Tag; typedef struct Token_TokenInstruction_Token_InitializeMint_Body { From ef28c7f6c4ccb092aaefe524001d07b0c4aca2a8 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 20 Jul 2021 19:51:46 +0200 Subject: [PATCH 136/335] token: Clear close authority for native accounts (#2115) --- program/src/processor.rs | 47 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 44f66f4..276c3be 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -370,6 +370,10 @@ impl Processor { account.delegate = COption::None; account.delegated_amount = 0; + + if account.is_native() { + account.close_authority = COption::None; + } } AuthorityType::CloseAccount => { let authority = account.close_authority.unwrap_or(account.owner); @@ -5066,6 +5070,9 @@ mod tests { let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let owner3_key = Pubkey::new_unique(); let mut rent_sysvar = rent_sysvar(); // initialize native account @@ -5205,13 +5212,49 @@ mod tests { assert!(account.is_native()); assert_eq!(account.amount, 40); + // set close authority + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner3_key), + AuthorityType::CloseAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.close_authority, COption::Some(owner3_key)); + + // set new account owner + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // close authority cleared + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.close_authority, COption::None); + // close native account do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), vec![ &mut account_account, &mut account3_account, - &mut owner_account, + &mut owner2_account, ], ) .unwrap(); From 8cec4d41cc77e6311199acbc094682a24409dde1 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 20 Jul 2021 23:40:32 +0200 Subject: [PATCH 137/335] token: Bump to 3.2.0 everywhere (#2116) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 74b77da..f1dc7be 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.1.1" +version = "3.2.0" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From fdfc0393f6a9284b392ff79b1364df3fd93127a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jul 2021 23:02:28 +0000 Subject: [PATCH 138/335] build(deps): bump num_enum from 0.5.1 to 0.5.2 (#2119) Bumps [num_enum](https://github.com/illicitonion/num_enum) from 0.5.1 to 0.5.2. - [Release notes](https://github.com/illicitonion/num_enum/releases) - [Commits](https://github.com/illicitonion/num_enum/compare/0.5.1...0.5.2) --- updated-dependencies: - dependency-name: num_enum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index f1dc7be..b370b22 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -15,7 +15,7 @@ no-entrypoint = [] arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" -num_enum = "0.5.1" +num_enum = "0.5.2" solana-program = "1.7.4" thiserror = "1.0" From 639970ca5ddc9ef422bfdd7eb35b755f0c80c12a Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 23 Jul 2021 10:47:06 -0600 Subject: [PATCH 139/335] Bump solana crates (#2139) --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index b370b22..2bcc091 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.2" -solana-program = "1.7.4" +solana-program = "1.7.7" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.7.4" +solana-sdk = "1.7.7" [lib] crate-type = ["cdylib", "lib"] From 7c5d7a236b7d08ed65fc35bb58f6a822d9774dd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Aug 2021 11:16:44 +0000 Subject: [PATCH 140/335] build(deps): bump num_enum from 0.5.2 to 0.5.3 (#2207) Bumps [num_enum](https://github.com/illicitonion/num_enum) from 0.5.2 to 0.5.3. - [Release notes](https://github.com/illicitonion/num_enum/releases) - [Commits](https://github.com/illicitonion/num_enum/compare/0.5.2...0.5.3) --- updated-dependencies: - dependency-name: num_enum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 2bcc091..b578ada 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -15,7 +15,7 @@ no-entrypoint = [] arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" -num_enum = "0.5.2" +num_enum = "0.5.3" solana-program = "1.7.7" thiserror = "1.0" From 3ddb1a9e0676f19ea72f26fcc45e25268115eafc Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 13 Aug 2021 11:59:38 -0700 Subject: [PATCH 141/335] Add InitializeMint2/InitializeMultisig2/InitializeAccount3 instructions --- program/src/instruction.rs | 197 ++++++++++++++++++++++++++++++++++- program/src/lib.rs | 2 +- program/src/processor.rs | 204 +++++++++++++++++++++++++++++++++++-- 3 files changed, 390 insertions(+), 13 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 3e9629a..c5936cf 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -373,6 +373,42 @@ pub enum TokenInstruction { /// /// 0. `[writable]` The native token account to sync with its underlying lamports. SyncNative, + /// Like InitializeAccount2, but does not require the Rent sysvar to be provided + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// 1. `[]` The mint this account will be associated with. + InitializeAccount3 { + /// The new account's owner/multisignature. + owner: Pubkey, + }, + /// Like InitializeMultisig, but does not require the Rent sysvar to be provided + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The multisignature account to initialize. + /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= + /// 11. + InitializeMultisig2 { + /// The number of signers (M) required to validate this multisignature + /// account. + m: u8, + }, + /// Like InitializeMint, but does not require the Rent sysvar to be provided + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The mint to initialize. + /// + InitializeMint2 { + /// Number of base 10 digits to the right of the decimal place. + decimals: u8, + /// The authority/multisignature to mint tokens. + mint_authority: Pubkey, + /// The freeze authority/multisignature of the mint. + freeze_authority: COption, + }, } impl TokenInstruction { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). @@ -475,7 +511,24 @@ impl TokenInstruction { Self::InitializeAccount2 { owner } } 17 => Self::SyncNative, - + 18 => { + let (owner, _rest) = Self::unpack_pubkey(rest)?; + Self::InitializeAccount3 { owner } + } + 19 => { + let &m = rest.get(0).ok_or(InvalidInstruction)?; + Self::InitializeMultisig2 { m } + } + 20 => { + let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?; + let (mint_authority, rest) = Self::unpack_pubkey(rest)?; + let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?; + Self::InitializeMint2 { + mint_authority, + freeze_authority, + decimals, + } + } _ => return Err(TokenError::InvalidInstruction.into()), }) } @@ -554,6 +607,24 @@ impl TokenInstruction { &Self::SyncNative => { buf.push(17); } + &Self::InitializeAccount3 { owner } => { + buf.push(18); + buf.extend_from_slice(owner.as_ref()); + } + &Self::InitializeMultisig2 { m } => { + buf.push(19); + buf.push(m); + } + &Self::InitializeMint2 { + ref mint_authority, + ref freeze_authority, + decimals, + } => { + buf.push(20); + buf.push(decimals); + buf.extend_from_slice(mint_authority.as_ref()); + Self::pack_pubkey_option(freeze_authority, &mut buf); + } }; buf } @@ -655,6 +726,32 @@ pub fn initialize_mint( }) } +/// Creates a `InitializeMint2` instruction. +pub fn initialize_mint2( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, + mint_authority_pubkey: &Pubkey, + freeze_authority_pubkey: Option<&Pubkey>, + decimals: u8, +) -> Result { + check_program_account(token_program_id)?; + let freeze_authority = freeze_authority_pubkey.cloned().into(); + let data = TokenInstruction::InitializeMint2 { + mint_authority: *mint_authority_pubkey, + freeze_authority, + decimals, + } + .pack(); + + let accounts = vec![AccountMeta::new(*mint_pubkey, false)]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + /// Creates a `InitializeAccount` instruction. pub fn initialize_account( token_program_id: &Pubkey, @@ -705,6 +802,31 @@ pub fn initialize_account2( }) } +/// Creates a `InitializeAccount3` instruction. +pub fn initialize_account3( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, + mint_pubkey: &Pubkey, + owner_pubkey: &Pubkey, +) -> Result { + check_program_account(token_program_id)?; + let data = TokenInstruction::InitializeAccount3 { + owner: *owner_pubkey, + } + .pack(); + + let accounts = vec![ + AccountMeta::new(*account_pubkey, false), + AccountMeta::new_readonly(*mint_pubkey, false), + ]; + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + /// Creates a `InitializeMultisig` instruction. pub fn initialize_multisig( token_program_id: &Pubkey, @@ -735,6 +857,35 @@ pub fn initialize_multisig( }) } +/// Creates a `InitializeMultisig2` instruction. +pub fn initialize_multisig2( + token_program_id: &Pubkey, + multisig_pubkey: &Pubkey, + signer_pubkeys: &[&Pubkey], + m: u8, +) -> Result { + check_program_account(token_program_id)?; + if !is_valid_signer_index(m as usize) + || !is_valid_signer_index(signer_pubkeys.len()) + || m as usize > signer_pubkeys.len() + { + return Err(ProgramError::MissingRequiredSignature); + } + let data = TokenInstruction::InitializeMultisig2 { m }.pack(); + + let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len()); + accounts.push(AccountMeta::new(*multisig_pubkey, false)); + for signer_pubkey in signer_pubkeys.iter() { + accounts.push(AccountMeta::new_readonly(**signer_pubkey, false)); + } + + Ok(Instruction { + program_id: *token_program_id, + accounts, + data, + }) +} + /// Creates a `Transfer` instruction. pub fn transfer( token_program_id: &Pubkey, @@ -1323,5 +1474,49 @@ mod test { assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeAccount3 { + owner: Pubkey::new(&[2u8; 32]), + }; + let packed = check.pack(); + let mut expect = vec![18u8]; + expect.extend_from_slice(&[2u8; 32]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeMultisig2 { m: 1 }; + let packed = check.pack(); + let expect = Vec::from([19u8, 1]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeMint2 { + decimals: 2, + mint_authority: Pubkey::new(&[1u8; 32]), + freeze_authority: COption::None, + }; + let packed = check.pack(); + let mut expect = Vec::from([20u8, 2]); + expect.extend_from_slice(&[1u8; 32]); + expect.extend_from_slice(&[0]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeMint2 { + decimals: 2, + mint_authority: Pubkey::new(&[2u8; 32]), + freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), + }; + let packed = check.pack(); + let mut expect = vec![20u8, 2]; + expect.extend_from_slice(&[2u8; 32]); + expect.extend_from_slice(&[1]); + expect.extend_from_slice(&[3u8; 32]); + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); } } diff --git a/program/src/lib.rs b/program/src/lib.rs index 529aaa1..4dda68d 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -1,5 +1,5 @@ #![deny(missing_docs)] -#![forbid(unsafe_code)] +#![cfg_attr(not(test), forbid(unsafe_code))] //! An ERC20-like Token program for the Solana blockchain diff --git a/program/src/processor.rs b/program/src/processor.rs index 276c3be..0587595 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -21,17 +21,21 @@ use solana_program::{ /// Program state handler. pub struct Processor {} impl Processor { - /// Processes an [InitializeMint](enum.TokenInstruction.html) instruction. - pub fn process_initialize_mint( + fn _process_initialize_mint( accounts: &[AccountInfo], decimals: u8, mint_authority: Pubkey, freeze_authority: COption, + rent_sysvar_account: bool, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let mint_info = next_account_info(account_info_iter)?; let mint_data_len = mint_info.data_len(); - let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; + let rent = if rent_sysvar_account { + Rent::from_account_info(next_account_info(account_info_iter)?)? + } else { + Rent::get()? + }; let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow())?; if mint.is_initialized { @@ -52,9 +56,30 @@ impl Processor { Ok(()) } + /// Processes an [InitializeMint](enum.TokenInstruction.html) instruction. + pub fn process_initialize_mint( + accounts: &[AccountInfo], + decimals: u8, + mint_authority: Pubkey, + freeze_authority: COption, + ) -> ProgramResult { + Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, true) + } + + /// Processes an [InitializeMint2](enum.TokenInstruction.html) instruction. + pub fn process_initialize_mint2( + accounts: &[AccountInfo], + decimals: u8, + mint_authority: Pubkey, + freeze_authority: COption, + ) -> ProgramResult { + Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, false) + } + fn _process_initialize_account( accounts: &[AccountInfo], owner: Option<&Pubkey>, + rent_sysvar_account: bool, ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let new_account_info = next_account_info(account_info_iter)?; @@ -65,7 +90,11 @@ impl Processor { next_account_info(account_info_iter)?.key }; let new_account_info_data_len = new_account_info.data_len(); - let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; + let rent = if rent_sysvar_account { + Rent::from_account_info(next_account_info(account_info_iter)?)? + } else { + Rent::get()? + }; let mut account = Account::unpack_unchecked(&new_account_info.data.borrow())?; if account.is_initialized() { @@ -105,20 +134,32 @@ impl Processor { /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { - Self::_process_initialize_account(accounts, None) + Self::_process_initialize_account(accounts, None, true) } /// Processes an [InitializeAccount2](enum.TokenInstruction.html) instruction. pub fn process_initialize_account2(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { - Self::_process_initialize_account(accounts, Some(&owner)) + Self::_process_initialize_account(accounts, Some(&owner), true) } - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. - pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { + /// Processes an [InitializeAccount3](enum.TokenInstruction.html) instruction. + pub fn process_initialize_account3(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { + Self::_process_initialize_account(accounts, Some(&owner), false) + } + + fn _process_initialize_multisig( + accounts: &[AccountInfo], + m: u8, + rent_sysvar_account: bool, + ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let multisig_info = next_account_info(account_info_iter)?; let multisig_info_data_len = multisig_info.data_len(); - let rent = &Rent::from_account_info(next_account_info(account_info_iter)?)?; + let rent = if rent_sysvar_account { + Rent::from_account_info(next_account_info(account_info_iter)?)? + } else { + Rent::get()? + }; let mut multisig = Multisig::unpack_unchecked(&multisig_info.data.borrow())?; if multisig.is_initialized { @@ -148,6 +189,16 @@ impl Processor { Ok(()) } + /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. + pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { + Self::_process_initialize_multisig(accounts, m, true) + } + + /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) instruction. + pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { + Self::_process_initialize_multisig(accounts, m, false) + } + /// Processes a [Transfer](enum.TokenInstruction.html) instruction. pub fn process_transfer( program_id: &Pubkey, @@ -688,6 +739,14 @@ impl Processor { msg!("Instruction: InitializeMint"); Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority) } + TokenInstruction::InitializeMint2 { + decimals, + mint_authority, + freeze_authority, + } => { + msg!("Instruction: InitializeMint2"); + Self::process_initialize_mint2(accounts, decimals, mint_authority, freeze_authority) + } TokenInstruction::InitializeAccount => { msg!("Instruction: InitializeAccount"); Self::process_initialize_account(accounts) @@ -696,10 +755,18 @@ impl Processor { msg!("Instruction: InitializeAccount2"); Self::process_initialize_account2(accounts, owner) } + TokenInstruction::InitializeAccount3 { owner } => { + msg!("Instruction: InitializeAccount3"); + Self::process_initialize_account3(accounts, owner) + } TokenInstruction::InitializeMultisig { m } => { msg!("Instruction: InitializeMultisig"); Self::process_initialize_multisig(accounts, m) } + TokenInstruction::InitializeMultisig2 { m } => { + msg!("Instruction: InitializeMultisig2"); + Self::process_initialize_multisig2(accounts, m) + } TokenInstruction::Transfer { amount } => { msg!("Instruction: Transfer"); Self::process_transfer(program_id, accounts, amount, None) @@ -849,16 +916,60 @@ mod tests { use super::*; use crate::instruction::*; use solana_program::{ - account_info::IntoAccountInfo, clock::Epoch, instruction::Instruction, sysvar::rent, + account_info::IntoAccountInfo, clock::Epoch, instruction::Instruction, program_error, + sysvar::rent, }; use solana_sdk::account::{ create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, }; + struct SyscallStubs {} + impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs { + fn sol_log(&self, _message: &str) {} + + fn sol_invoke_signed( + &self, + _instruction: &Instruction, + _account_infos: &[AccountInfo], + _signers_seeds: &[&[&[u8]]], + ) -> ProgramResult { + Err(ProgramError::Custom(42)) // Not supported + } + + fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 { + program_error::UNSUPPORTED_SYSVAR + } + + fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 { + program_error::UNSUPPORTED_SYSVAR + } + + #[allow(deprecated)] + fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 { + program_error::UNSUPPORTED_SYSVAR + } + + fn sol_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 { + unsafe { + *(var_addr as *mut _ as *mut Rent) = Rent::default(); + } + solana_program::entrypoint::SUCCESS + } + } + fn do_process_instruction( instruction: Instruction, accounts: Vec<&mut SolanaAccount>, ) -> ProgramResult { + { + use std::sync::Once; + static ONCE: Once = Once::new(); + + ONCE.call_once(|| { + solana_sdk::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {})); + }); + } + let mut meta = instruction .accounts .iter() @@ -1072,6 +1183,53 @@ mod tests { assert_eq!(mint.freeze_authority, COption::Some(owner_key)); } + #[test] + fn test_initialize_mint2() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + + // mint is not rent exempt + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account] + ) + ); + + mint_account.lamports = mint_minimum_balance(); + + // create new mint + do_process_instruction( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // create twice + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), + vec![&mut mint_account] + ) + ); + + // create another mint that can freeze + do_process_instruction( + initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account], + ) + .unwrap(); + let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); + assert_eq!(mint.freeze_authority, COption::Some(owner_key)); + } + #[test] fn test_initialize_mint_account() { let program_id = crate::id(); @@ -4216,6 +4374,17 @@ mod tests { ], ) ); + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account, + &mut rent_sysvar, + &mut account_info_iter.next().unwrap(), + ], + ) + ); multisig_account.lamports = multisig_minimum_balance(); @@ -5806,7 +5975,7 @@ mod tests { } #[test] - fn test_initialize_account2() { + fn test_initialize_account2_and_3() { let program_id = crate::id(); let account_key = Pubkey::new_unique(); let mut account_account = SolanaAccount::new( @@ -5819,6 +5988,11 @@ mod tests { Account::get_packed_len(), &program_id, ); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); let owner_key = Pubkey::new_unique(); let mut owner_account = SolanaAccount::default(); let mint_key = Pubkey::new_unique(); @@ -5851,6 +6025,14 @@ mod tests { .unwrap(); assert_eq!(account_account, account2_account); + + do_process_instruction( + initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + assert_eq!(account_account, account3_account); } #[test] From bf55c6cabe355f76f46045031552e047b73ebbcc Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 13 Aug 2021 18:55:06 -0700 Subject: [PATCH 142/335] review feedback --- program/src/processor.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 0587595..a1d86f0 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -4374,19 +4374,9 @@ mod tests { ], ) ); - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account, - &mut rent_sysvar, - &mut account_info_iter.next().unwrap(), - ], - ) - ); multisig_account.lamports = multisig_minimum_balance(); + let mut multisig_account2 = multisig_account.clone(); // single signer let account_info_iter = &mut signer_accounts.iter_mut(); @@ -4400,6 +4390,17 @@ mod tests { ) .unwrap(); + // single signer using `initialize_multisig2` + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account2, + &mut account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + // multiple signer let account_info_iter = &mut signer_accounts.iter_mut(); do_process_instruction( @@ -6028,7 +6029,7 @@ mod tests { do_process_instruction( initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account, &mut rent_sysvar], + vec![&mut account3_account, &mut mint_account], ) .unwrap(); From fc23ff759c4d2517622ebb78ce469a8d752be71f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Aug 2021 11:15:31 +0000 Subject: [PATCH 143/335] build(deps): bump num_enum from 0.5.3 to 0.5.4 (#2293) Bumps [num_enum](https://github.com/illicitonion/num_enum) from 0.5.3 to 0.5.4. - [Release notes](https://github.com/illicitonion/num_enum/releases) - [Commits](https://github.com/illicitonion/num_enum/compare/0.5.3...0.5.4) --- updated-dependencies: - dependency-name: num_enum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index b578ada..538e0c0 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -15,7 +15,7 @@ no-entrypoint = [] arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" -num_enum = "0.5.3" +num_enum = "0.5.4" solana-program = "1.7.7" thiserror = "1.0" From efd82bd585055d26b1e88d19ce7769ae760905b8 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 30 Aug 2021 12:20:33 -0700 Subject: [PATCH 144/335] Upgrade to Solana 1.7.11 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 538e0c0..9637ccc 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.7.7" +solana-program = "1.7.11" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.7.7" +solana-sdk = "1.7.11" [lib] crate-type = ["cdylib", "lib"] From d3edd78e0db6c48226b87a4697f7f9fdd2f9f175 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Tue, 12 Oct 2021 09:14:32 -0700 Subject: [PATCH 145/335] Upgrade to Solana 1.8.0 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 9637ccc..b2def07 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.7.11" +solana-program = "1.8.0" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.7.11" +solana-sdk = "1.8.0" [lib] crate-type = ["cdylib", "lib"] From b6a88a6b6af7ae694680fc0a091ecbf2d34719b5 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Wed, 20 Oct 2021 22:20:12 -0700 Subject: [PATCH 146/335] Upgrade to Solana v1.8.1 --- program/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index b2def07..a199dab 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -16,11 +16,11 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.8.0" +solana-program = "1.8.1" thiserror = "1.0" [dev-dependencies] -solana-sdk = "1.8.0" +solana-sdk = "1.8.1" [lib] crate-type = ["cdylib", "lib"] From 838283d9bc26898da54c5e298bc28af41a9c4318 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 16 Nov 2021 23:15:45 +0100 Subject: [PATCH 147/335] token: Transition perf-monitor to solana-program-test (#2586) * token: Transition perf-monitor to solana-program-test * fmt * Refactor for clarity --- program/Cargo.toml | 2 + program/tests/action.rs | 140 +++++++++++ program/tests/assert_instruction_count.rs | 284 ++++++++++++++++++++++ 3 files changed, 426 insertions(+) create mode 100644 program/tests/action.rs create mode 100644 program/tests/assert_instruction_count.rs diff --git a/program/Cargo.toml b/program/Cargo.toml index a199dab..5b9a976 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -10,6 +10,7 @@ exclude = ["js/**"] [features] no-entrypoint = [] +test-bpf = [] [dependencies] arrayref = "0.3.6" @@ -20,6 +21,7 @@ solana-program = "1.8.1" thiserror = "1.0" [dev-dependencies] +solana-program-test = "1.8.1" solana-sdk = "1.8.1" [lib] diff --git a/program/tests/action.rs b/program/tests/action.rs new file mode 100644 index 0000000..0a67538 --- /dev/null +++ b/program/tests/action.rs @@ -0,0 +1,140 @@ +use { + solana_program_test::BanksClient, + solana_sdk::{ + hash::Hash, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + transport::TransportError, + }, + spl_token::{ + id, instruction, + state::{Account, Mint}, + }, +}; + +pub async fn create_mint( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + pool_mint: &Keypair, + manager: &Pubkey, + decimals: u8, +) -> Result<(), TransportError> { + let rent = banks_client.get_rent().await.unwrap(); + let mint_rent = rent.minimum_balance(Mint::LEN); + + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &pool_mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &id(), + ), + instruction::initialize_mint(&id(), &pool_mint.pubkey(), manager, None, decimals) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, pool_mint], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn create_account( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + account: &Keypair, + pool_mint: &Pubkey, + owner: &Pubkey, +) -> Result<(), TransportError> { + let rent = banks_client.get_rent().await.unwrap(); + let account_rent = rent.minimum_balance(Account::LEN); + + let transaction = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &payer.pubkey(), + &account.pubkey(), + account_rent, + Account::LEN as u64, + &id(), + ), + instruction::initialize_account(&id(), &account.pubkey(), pool_mint, owner).unwrap(), + ], + Some(&payer.pubkey()), + &[payer, account], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn mint_to( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + mint: &Pubkey, + account: &Pubkey, + mint_authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::mint_to(&id(), mint, account, &mint_authority.pubkey(), &[], amount) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, mint_authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn transfer( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + source: &Pubkey, + destination: &Pubkey, + authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::transfer(&id(), source, destination, &authority.pubkey(), &[], amount) + .unwrap(), + ], + Some(&payer.pubkey()), + &[payer, authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} + +pub async fn burn( + banks_client: &mut BanksClient, + payer: &Keypair, + recent_blockhash: Hash, + mint: &Pubkey, + account: &Pubkey, + authority: &Keypair, + amount: u64, +) -> Result<(), TransportError> { + let transaction = Transaction::new_signed_with_payer( + &[instruction::burn(&id(), account, mint, &authority.pubkey(), &[], amount).unwrap()], + Some(&payer.pubkey()), + &[payer, authority], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await?; + Ok(()) +} diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs new file mode 100644 index 0000000..858bd55 --- /dev/null +++ b/program/tests/assert_instruction_count.rs @@ -0,0 +1,284 @@ +#![cfg(feature = "test-bpf")] + +mod action; +use { + solana_program_test::{processor, tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, + spl_token::{ + id, instruction, + processor::Processor, + state::{Account, Mint}, + }, +}; + +const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; + +#[tokio::test] +async fn initialize_mint() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(2_500); // last known 2252 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner_key = Pubkey::new_unique(); + let mint = Keypair::new(); + let decimals = 9; + + let rent = banks_client.get_rent().await.unwrap(); + let mint_rent = rent.minimum_balance(Mint::LEN); + let transaction = Transaction::new_signed_with_payer( + &[system_instruction::create_account( + &payer.pubkey(), + &mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &id(), + )], + Some(&payer.pubkey()), + &[&payer, &mint], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[ + instruction::initialize_mint(&id(), &mint.pubkey(), &owner_key, None, decimals) + .unwrap(), + ], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn initialize_account() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 3284 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + let rent = banks_client.get_rent().await.unwrap(); + let account_rent = rent.minimum_balance(Account::LEN); + let transaction = Transaction::new_signed_with_payer( + &[system_instruction::create_account( + &payer.pubkey(), + &account.pubkey(), + account_rent, + Account::LEN as u64, + &id(), + )], + Some(&payer.pubkey()), + &[&payer, &account], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[instruction::initialize_account( + &id(), + &account.pubkey(), + &mint.pubkey(), + &owner.pubkey(), + ) + .unwrap()], + Some(&payer.pubkey()), + &[&payer], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn mint_to() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2668 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &account, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[instruction::mint_to( + &id(), + &mint.pubkey(), + &account.pubkey(), + &owner.pubkey(), + &[], + TRANSFER_AMOUNT, + ) + .unwrap()], + Some(&payer.pubkey()), + &[&payer, &owner], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} + +#[tokio::test] +async fn transfer() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2972 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let source = Keypair::new(); + let destination = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &source, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &destination, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + action::mint_to( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &source.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); + + action::transfer( + &mut banks_client, + &payer, + recent_blockhash, + &source.pubkey(), + &destination.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn burn() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_bpf_compute_max_units(4_000); // last known 2655 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &account, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + action::mint_to( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &account.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); + + action::burn( + &mut banks_client, + &payer, + recent_blockhash, + &mint.pubkey(), + &account.pubkey(), + &owner, + TRANSFER_AMOUNT, + ) + .await + .unwrap(); +} From 6858f1fdcd0f41e72cd32ae386598dbcfe3283d2 Mon Sep 17 00:00:00 2001 From: Victor Pontis Date: Sun, 28 Nov 2021 20:16:33 -0800 Subject: [PATCH 148/335] Update comment on state.rs regarding is_native MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I was confused when reading this comment and had to read the code to realize that the comment isn't a typo. (Btw, let me know if this kind of small changes are helpful or not 👍.) --- program/src/state.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/src/state.rs b/program/src/state.rs index c35f342..15cc183 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -95,9 +95,9 @@ pub struct Account { pub delegate: COption, /// The account's state pub state: AccountState, - /// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account - /// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped - /// SOL accounts do not drop below this threshold. + /// If is_native.is_some, this is a native token, and the value logs the rent-exempt reserve. An + /// Account is required to be rent-exempt, so the value is used by the Processor to ensure that + /// wrapped SOL accounts do not drop below this threshold. pub is_native: COption, /// The amount delegated pub delegated_amount: u64, From 0b038a139836f9778ebf44a9128570b00298c8e6 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 9 Dec 2021 22:12:22 -0800 Subject: [PATCH 149/335] Update to Rust 1.57.0 --- program/src/processor.rs | 93 +++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index a1d86f0..5ab0002 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -4370,7 +4370,7 @@ mod tests { vec![ &mut multisig_account, &mut rent_sysvar, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) ); @@ -4385,7 +4385,7 @@ mod tests { vec![ &mut multisig_account, &mut rent_sysvar, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4394,10 +4394,7 @@ mod tests { let account_info_iter = &mut signer_accounts.iter_mut(); do_process_instruction( initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account2, - &mut account_info_iter.next().unwrap(), - ], + vec![&mut multisig_account2, account_info_iter.next().unwrap()], ) .unwrap(); @@ -4414,17 +4411,17 @@ mod tests { vec![ &mut multisig_delegate_account, &mut rent_sysvar, - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4482,7 +4479,7 @@ mod tests { &mut mint_account, &mut account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4503,7 +4500,7 @@ mod tests { &mut account, &mut multisig_delegate_account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4524,7 +4521,7 @@ mod tests { &mut account, &mut account2_account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4545,17 +4542,17 @@ mod tests { &mut account, &mut account2_account, &mut multisig_delegate_account, - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4576,7 +4573,7 @@ mod tests { &mut mint_account, &mut account2_account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4597,7 +4594,7 @@ mod tests { &mut account, &mut mint_account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4618,17 +4615,17 @@ mod tests { &mut account, &mut mint_account, &mut multisig_delegate_account, - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4680,7 +4677,7 @@ mod tests { &mut mint2_account, &mut account3_account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4698,7 +4695,7 @@ mod tests { &mut account3_account, &mut mint2_account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4718,7 +4715,7 @@ mod tests { vec![ &mut mint_account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); @@ -4738,7 +4735,7 @@ mod tests { vec![ &mut account, &mut multisig_account, - &mut account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), ], ) .unwrap(); From 37293bb13d7051639d345a7cba9a99eb15f13f1e Mon Sep 17 00:00:00 2001 From: Dmitri Makarov Date: Mon, 20 Dec 2021 15:29:36 -0800 Subject: [PATCH 150/335] Increase compute max units due to changes in handling of memory ops (#2653) --- program/tests/assert_instruction_count.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs index 858bd55..64f4e7c 100644 --- a/program/tests/assert_instruction_count.rs +++ b/program/tests/assert_instruction_count.rs @@ -22,7 +22,7 @@ const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; #[tokio::test] async fn initialize_mint() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(2_500); // last known 2252 + pt.set_bpf_compute_max_units(5_000); // last known 2252 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner_key = Pubkey::new_unique(); @@ -60,7 +60,7 @@ async fn initialize_mint() { #[tokio::test] async fn initialize_account() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(4_000); // last known 3284 + pt.set_bpf_compute_max_units(6_000); // last known 3284 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner = Keypair::new(); @@ -112,7 +112,7 @@ async fn initialize_account() { #[tokio::test] async fn mint_to() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(4_000); // last known 2668 + pt.set_bpf_compute_max_units(6_000); // last known 2668 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner = Keypair::new(); @@ -161,7 +161,7 @@ async fn mint_to() { #[tokio::test] async fn transfer() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(4_000); // last known 2972 + pt.set_bpf_compute_max_units(7_000); // last known 2972 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner = Keypair::new(); @@ -229,7 +229,7 @@ async fn transfer() { #[tokio::test] async fn burn() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(4_000); // last known 2655 + pt.set_bpf_compute_max_units(6_000); // last known 2655 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner = Keypair::new(); From 96d2f61146435fcc9dbfe216c8008bf61073ac3b Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 28 Dec 2021 23:02:47 -0500 Subject: [PATCH 151/335] Update SDK to 1.9.2, fix warnings (#2674) * Update SDK to 1.9.2, fix warnings * Upgrade honggfuzz * Use `get_latest_blockhash` correctly --- program/Cargo.toml | 6 +++--- program/tests/assert_instruction_count.rs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 5b9a976..c62d27a 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,12 +17,12 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.8.1" +solana-program = "1.9.2" thiserror = "1.0" [dev-dependencies] -solana-program-test = "1.8.1" -solana-sdk = "1.8.1" +solana-program-test = "1.9.2" +solana-sdk = "1.9.2" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs index 64f4e7c..27054fc 100644 --- a/program/tests/assert_instruction_count.rs +++ b/program/tests/assert_instruction_count.rs @@ -22,7 +22,7 @@ const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; #[tokio::test] async fn initialize_mint() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(5_000); // last known 2252 + pt.set_compute_max_units(5_000); // last known 2252 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner_key = Pubkey::new_unique(); @@ -60,7 +60,7 @@ async fn initialize_mint() { #[tokio::test] async fn initialize_account() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(6_000); // last known 3284 + pt.set_compute_max_units(6_000); // last known 3284 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner = Keypair::new(); @@ -112,7 +112,7 @@ async fn initialize_account() { #[tokio::test] async fn mint_to() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(6_000); // last known 2668 + pt.set_compute_max_units(6_000); // last known 2668 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner = Keypair::new(); @@ -161,7 +161,7 @@ async fn mint_to() { #[tokio::test] async fn transfer() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(7_000); // last known 2972 + pt.set_compute_max_units(7_000); // last known 2972 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner = Keypair::new(); @@ -229,7 +229,7 @@ async fn transfer() { #[tokio::test] async fn burn() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_bpf_compute_max_units(6_000); // last known 2655 + pt.set_compute_max_units(6_000); // last known 2655 let (mut banks_client, payer, recent_blockhash) = pt.start().await; let owner = Keypair::new(); From 65bab0b0ca590de7fffbd4a4d079db3b382c0e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Piotrowski?= Date: Wed, 5 Jan 2022 23:11:31 +0100 Subject: [PATCH 152/335] token tests p1 (#2700) * token tests p1 * token tests - address review comments * fix cs --- program/src/state.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/program/src/state.rs b/program/src/state.rs index 15cc183..71f0d40 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -286,3 +286,78 @@ fn unpack_coption_u64(src: &[u8; 12]) -> Result, ProgramError> { _ => Err(ProgramError::InvalidAccountData), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mint_unpack_from_slice() { + let src: [u8; 82] = [0; 82]; + let mint = Mint::unpack_from_slice(&src).unwrap(); + assert!(!mint.is_initialized); + + let mut src: [u8; 82] = [0; 82]; + src[45] = 2; + let mint = Mint::unpack_from_slice(&src).unwrap_err(); + assert_eq!(mint, ProgramError::InvalidAccountData); + } + + #[test] + fn test_account_state() { + let account_state = AccountState::default(); + assert_eq!(account_state, AccountState::Uninitialized); + } + + #[test] + fn test_multisig_unpack_from_slice() { + let src: [u8; 355] = [0; 355]; + let multisig = Multisig::unpack_from_slice(&src).unwrap(); + assert_eq!(multisig.m, 0); + assert_eq!(multisig.n, 0); + assert!(!multisig.is_initialized); + + let mut src: [u8; 355] = [0; 355]; + src[0] = 1; + src[1] = 1; + src[2] = 1; + let multisig = Multisig::unpack_from_slice(&src).unwrap(); + assert_eq!(multisig.m, 1); + assert_eq!(multisig.n, 1); + assert!(multisig.is_initialized); + + let mut src: [u8; 355] = [0; 355]; + src[2] = 2; + let multisig = Multisig::unpack_from_slice(&src).unwrap_err(); + assert_eq!(multisig, ProgramError::InvalidAccountData); + } + + #[test] + fn test_unpack_coption_key() { + let src: [u8; 36] = [0; 36]; + let result = unpack_coption_key(&src).unwrap(); + assert_eq!(result, COption::None); + + let mut src: [u8; 36] = [0; 36]; + src[1] = 1; + let result = unpack_coption_key(&src).unwrap_err(); + assert_eq!(result, ProgramError::InvalidAccountData); + } + + #[test] + fn test_unpack_coption_u64() { + let src: [u8; 12] = [0; 12]; + let result = unpack_coption_u64(&src).unwrap(); + assert_eq!(result, COption::None); + + let mut src: [u8; 12] = [0; 12]; + src[0] = 1; + let result = unpack_coption_u64(&src).unwrap(); + assert_eq!(result, COption::Some(0)); + + let mut src: [u8; 12] = [0; 12]; + src[1] = 1; + let result = unpack_coption_u64(&src).unwrap_err(); + assert_eq!(result, ProgramError::InvalidAccountData); + } +} From 9cf9c36431651bee2024675ee17d135f0adc211a Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 21 Jan 2022 01:03:00 +0100 Subject: [PATCH 153/335] token: Zeroize data on account close (#2763) --- program/src/processor.rs | 343 +++++++++++++++++----- program/tests/assert_instruction_count.rs | 48 +++ 2 files changed, 320 insertions(+), 71 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 5ab0002..d0045a4 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -12,9 +12,10 @@ use solana_program::{ entrypoint::ProgramResult, msg, program_error::{PrintProgramError, ProgramError}, + program_memory::{sol_memcmp, sol_memset}, program_option::COption, program_pack::{IsInitialized, Pack}, - pubkey::Pubkey, + pubkey::{Pubkey, PUBKEY_BYTES}, sysvar::{rent::Rent, Sysvar}, }; @@ -77,6 +78,7 @@ impl Processor { } fn _process_initialize_account( + program_id: &Pubkey, accounts: &[AccountInfo], owner: Option<&Pubkey>, rent_sysvar_account: bool, @@ -105,7 +107,9 @@ impl Processor { return Err(TokenError::NotRentExempt.into()); } - if *mint_info.key != crate::native_mint::id() { + let is_native_mint = Self::cmp_pubkeys(mint_info.key, &crate::native_mint::id()); + if !is_native_mint { + Self::check_account_owner(program_id, mint_info)?; let _ = Mint::unpack(&mint_info.data.borrow_mut()) .map_err(|_| Into::::into(TokenError::InvalidMint))?; } @@ -115,7 +119,7 @@ impl Processor { account.delegate = COption::None; account.delegated_amount = 0; account.state = AccountState::Initialized; - if *mint_info.key == crate::native_mint::id() { + if is_native_mint { let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len); account.is_native = COption::Some(rent_exempt_reserve); account.amount = new_account_info @@ -133,18 +137,29 @@ impl Processor { } /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { - Self::_process_initialize_account(accounts, None, true) + pub fn process_initialize_account( + program_id: &Pubkey, + accounts: &[AccountInfo], + ) -> ProgramResult { + Self::_process_initialize_account(program_id, accounts, None, true) } /// Processes an [InitializeAccount2](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account2(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { - Self::_process_initialize_account(accounts, Some(&owner), true) + pub fn process_initialize_account2( + program_id: &Pubkey, + accounts: &[AccountInfo], + owner: Pubkey, + ) -> ProgramResult { + Self::_process_initialize_account(program_id, accounts, Some(&owner), true) } /// Processes an [InitializeAccount3](enum.TokenInstruction.html) instruction. - pub fn process_initialize_account3(accounts: &[AccountInfo], owner: Pubkey) -> ProgramResult { - Self::_process_initialize_account(accounts, Some(&owner), false) + pub fn process_initialize_account3( + program_id: &Pubkey, + accounts: &[AccountInfo], + owner: Pubkey, + ) -> ProgramResult { + Self::_process_initialize_account(program_id, accounts, Some(&owner), false) } fn _process_initialize_multisig( @@ -228,12 +243,12 @@ impl Processor { if source_account.amount < amount { return Err(TokenError::InsufficientFunds.into()); } - if source_account.mint != dest_account.mint { + if !Self::cmp_pubkeys(&source_account.mint, &dest_account.mint) { return Err(TokenError::MintMismatch.into()); } if let Some((mint_info, expected_decimals)) = expected_mint_info { - if source_account.mint != *mint_info.key { + if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) { return Err(TokenError::MintMismatch.into()); } @@ -243,10 +258,10 @@ impl Processor { } } - let self_transfer = source_account_info.key == dest_account_info.key; + let self_transfer = Self::cmp_pubkeys(source_account_info.key, dest_account_info.key); match source_account.delegate { - COption::Some(ref delegate) if authority_info.key == delegate => { + COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => { Self::validate_owner( program_id, delegate, @@ -274,6 +289,11 @@ impl Processor { )?, }; + if self_transfer || amount == 0 { + Self::check_account_owner(program_id, source_account_info)?; + Self::check_account_owner(program_id, dest_account_info)?; + } + // This check MUST occur just before the amounts are manipulated // to ensure self-transfers are fully validated if self_transfer { @@ -333,7 +353,7 @@ impl Processor { } if let Some((mint_info, expected_decimals)) = expected_mint_info { - if source_account.mint != *mint_info.key { + if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) { return Err(TokenError::MintMismatch.into()); } @@ -504,7 +524,7 @@ impl Processor { if dest_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } - if mint_info.key != &dest_account.mint { + if !Self::cmp_pubkeys(mint_info.key, &dest_account.mint) { return Err(TokenError::MintMismatch.into()); } @@ -525,6 +545,11 @@ impl Processor { COption::None => return Err(TokenError::FixedSupply.into()), } + if amount == 0 { + Self::check_account_owner(program_id, mint_info)?; + Self::check_account_owner(program_id, dest_account_info)?; + } + dest_account.amount = dest_account .amount .checked_add(amount) @@ -566,7 +591,7 @@ impl Processor { if source_account.amount < amount { return Err(TokenError::InsufficientFunds.into()); } - if mint_info.key != &source_account.mint { + if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) { return Err(TokenError::MintMismatch.into()); } @@ -577,7 +602,7 @@ impl Processor { } match source_account.delegate { - COption::Some(ref delegate) if authority_info.key == delegate => { + COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => { Self::validate_owner( program_id, delegate, @@ -604,6 +629,11 @@ impl Processor { )?, } + if amount == 0 { + Self::check_account_owner(program_id, source_account_info)?; + Self::check_account_owner(program_id, mint_info)?; + } + source_account.amount = source_account .amount .checked_sub(amount) @@ -626,7 +656,11 @@ impl Processor { let dest_account_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; - let mut source_account = Account::unpack(&source_account_info.data.borrow())?; + if Self::cmp_pubkeys(source_account_info.key, dest_account_info.key) { + return Err(ProgramError::InvalidAccountData); + } + + let source_account = Account::unpack(&source_account_info.data.borrow())?; if !source_account.is_native() && source_account.amount != 0 { return Err(TokenError::NonNativeHasBalance.into()); } @@ -647,9 +681,8 @@ impl Processor { .ok_or(TokenError::Overflow)?; **source_account_info.lamports.borrow_mut() = 0; - source_account.amount = 0; - Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; + sol_memset(*source_account_info.data.borrow_mut(), 0, Account::LEN); Ok(()) } @@ -673,7 +706,7 @@ impl Processor { if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } - if mint_info.key != &source_account.mint { + if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) { return Err(TokenError::MintMismatch.into()); } @@ -703,10 +736,8 @@ impl Processor { pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let native_account_info = next_account_info(account_info_iter)?; + Self::check_account_owner(program_id, native_account_info)?; - if native_account_info.owner != program_id { - return Err(ProgramError::IncorrectProgramId); - } let mut native_account = Account::unpack(&native_account_info.data.borrow())?; if let COption::Some(rent_exempt_reserve) = native_account.is_native { @@ -749,15 +780,15 @@ impl Processor { } TokenInstruction::InitializeAccount => { msg!("Instruction: InitializeAccount"); - Self::process_initialize_account(accounts) + Self::process_initialize_account(program_id, accounts) } TokenInstruction::InitializeAccount2 { owner } => { msg!("Instruction: InitializeAccount2"); - Self::process_initialize_account2(accounts, owner) + Self::process_initialize_account2(program_id, accounts, owner) } TokenInstruction::InitializeAccount3 { owner } => { msg!("Instruction: InitializeAccount3"); - Self::process_initialize_account3(accounts, owner) + Self::process_initialize_account3(program_id, accounts, owner) } TokenInstruction::InitializeMultisig { m } => { msg!("Instruction: InitializeMultisig"); @@ -829,6 +860,21 @@ impl Processor { } } + /// Checks that the account is owned by the expected program + pub fn check_account_owner(program_id: &Pubkey, account_info: &AccountInfo) -> ProgramResult { + if !Self::cmp_pubkeys(program_id, account_info.owner) { + Err(ProgramError::IncorrectProgramId) + } else { + Ok(()) + } + } + + /// Checks two pubkeys for equality in a computationally cheap way using + /// `sol_memcmp` + pub fn cmp_pubkeys(a: &Pubkey, b: &Pubkey) -> bool { + sol_memcmp(a.as_ref(), b.as_ref(), PUBKEY_BYTES) == 0 + } + /// Validates owner(s) are present pub fn validate_owner( program_id: &Pubkey, @@ -836,10 +882,10 @@ impl Processor { owner_account_info: &AccountInfo, signers: &[AccountInfo], ) -> ProgramResult { - if expected_owner != owner_account_info.key { + if !Self::cmp_pubkeys(expected_owner, owner_account_info.key) { return Err(TokenError::OwnerMismatch.into()); } - if program_id == owner_account_info.owner + if Self::cmp_pubkeys(program_id, owner_account_info.owner) && owner_account_info.data_len() == Multisig::get_packed_len() { let multisig = Multisig::unpack(&owner_account_info.data.borrow())?; @@ -847,7 +893,7 @@ impl Processor { let mut matched = [false; MAX_SIGNERS]; for signer in signers.iter() { for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() { - if key == signer.key && !matched[position] { + if Self::cmp_pubkeys(key, signer.key) && !matched[position] { if !signer.is_signer { return Err(ProgramError::MissingRequiredSignature); } @@ -1279,6 +1325,23 @@ mod tests { ) .unwrap(); + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar + ], + ) + ); + mint_account.owner = program_id; + // create account do_process_instruction( initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), @@ -1782,6 +1845,38 @@ mod tests { ) ); + // account not owned by program + let not_program_id = Pubkey::new_unique(); + account_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + account_account.owner = program_id; + + // account 2 not owned by program + let not_program_id = Pubkey::new_unique(); + account2_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + account2_account.owner = program_id; + // transfer do_process_instruction( transfer( @@ -3819,6 +3914,30 @@ mod tests { ) ); + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + mint_account.owner = program_id; + + // account not owned by program + let not_program_id = Pubkey::new_unique(); + account_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + account_account.owner = program_id; + // uninitialized destination account assert_eq!( Err(ProgramError::UninitializedAccount), @@ -4199,6 +4318,30 @@ mod tests { ) ); + // account not owned by program + let not_program_id = Pubkey::new_unique(); + account_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + account_account.owner = program_id; + + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + mint_account.owner = program_id; + // mint mismatch assert_eq!( Err(TokenError::MintMismatch.into()), @@ -4902,22 +5045,8 @@ mod tests { } #[test] - fn test_close_account_dups() { + fn test_owner_close_account_dups() { let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_info: AccountInfo = (&account2_key, true, &mut account2_account).into(); let owner_key = Pubkey::new_unique(); let mint_key = Pubkey::new_unique(); let mut mint_account = @@ -4934,13 +5063,29 @@ mod tests { ) .unwrap(); + let to_close_key = Pubkey::new_unique(); + let mut to_close_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let to_close_account_info: AccountInfo = + (&to_close_key, true, &mut to_close_account).into(); + let destination_account_key = Pubkey::new_unique(); + let mut destination_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let destination_account_info: AccountInfo = + (&destination_account_key, true, &mut destination_account).into(); // create account do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), vec![ - account1_info.clone(), + to_close_account_info.clone(), mint_info.clone(), - account1_info.clone(), + to_close_account_info.clone(), rent_info.clone(), ], ) @@ -4950,41 +5095,89 @@ mod tests { do_process_instruction_dups( close_account( &program_id, - &account1_key, - &account2_key, - &account1_key, + &to_close_key, + &destination_account_key, + &to_close_key, &[], ) .unwrap(), vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), + to_close_account_info.clone(), + destination_account_info.clone(), + to_close_account_info.clone(), ], ) .unwrap(); + assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); + } - // source-close-authority close - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(account1_key); + #[test] + fn test_close_authority_close_account_dups() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + let to_close_key = Pubkey::new_unique(); + let mut to_close_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let to_close_account_info: AccountInfo = + (&to_close_key, true, &mut to_close_account).into(); + let destination_account_key = Pubkey::new_unique(); + let mut destination_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let destination_account_info: AccountInfo = + (&destination_account_key, true, &mut destination_account).into(); + // create account + do_process_instruction_dups( + initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), + vec![ + to_close_account_info.clone(), + mint_info.clone(), + to_close_account_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap(); + account.close_authority = COption::Some(to_close_key); account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + Account::pack(account, &mut to_close_account_info.data.borrow_mut()).unwrap(); do_process_instruction_dups( close_account( &program_id, - &account1_key, - &account2_key, - &account1_key, + &to_close_key, + &destination_account_key, + &to_close_key, &[], ) .unwrap(), vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), + to_close_account_info.clone(), + destination_account_info.clone(), + to_close_account_info.clone(), ], ) .unwrap(); + assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); } #[test] @@ -5206,10 +5399,7 @@ mod tests { ], ) .unwrap(); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account_account.lamports, 0); - assert_eq!(account.amount, 0); + assert_eq!(account2_account.data, [0u8; Account::LEN]); assert_eq!( account3_account.lamports, 3 * account_minimum_balance() + 2 + 42 @@ -5427,9 +5617,7 @@ mod tests { .unwrap(); assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); + assert_eq!(account_account.data, [0u8; Account::LEN]); } #[test] @@ -6116,6 +6304,19 @@ mod tests { ], ) .unwrap(); + + // fail sync, not owned by program + let not_program_id = Pubkey::new_unique(); + native_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + sync_native(&program_id, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); + native_account.owner = program_id; + let account = Account::unpack_unchecked(&native_account.data).unwrap(); assert!(account.is_native()); assert_eq!(account.amount, lamports); diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs index 27054fc..d663c54 100644 --- a/program/tests/assert_instruction_count.rs +++ b/program/tests/assert_instruction_count.rs @@ -282,3 +282,51 @@ async fn burn() { .await .unwrap(); } + +#[tokio::test] +async fn close_account() { + let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); + pt.set_compute_max_units(6_000); // last known 1783 + let (mut banks_client, payer, recent_blockhash) = pt.start().await; + + let owner = Keypair::new(); + let mint = Keypair::new(); + let account = Keypair::new(); + let decimals = 9; + + action::create_mint( + &mut banks_client, + &payer, + recent_blockhash, + &mint, + &owner.pubkey(), + decimals, + ) + .await + .unwrap(); + action::create_account( + &mut banks_client, + &payer, + recent_blockhash, + &account, + &mint.pubkey(), + &owner.pubkey(), + ) + .await + .unwrap(); + + let transaction = Transaction::new_signed_with_payer( + &[instruction::close_account( + &id(), + &account.pubkey(), + &owner.pubkey(), + &owner.pubkey(), + &[], + ) + .unwrap()], + Some(&payer.pubkey()), + &[&payer, &owner], + recent_blockhash, + ); + banks_client.process_transaction(transaction).await.unwrap(); +} From c46ed936475c1c327ec4d38c3d200726f07b3239 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 21 Jan 2022 01:47:02 +0100 Subject: [PATCH 154/335] token: Bump version to 3.3.0 (#2765) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index c62d27a..3dd1210 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.2.0" +version = "3.3.0" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 4c76c0d3e87e56f461c745767a646ce6c6e9592d Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 21 Jan 2022 22:52:10 -0700 Subject: [PATCH 155/335] Bump solana crates to v1.9.5 (#2780) * Bump solana crates to v1.9.5 * Update sol_set_return_data type signature and un-ignore test --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 3dd1210..76ee9f7 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,12 +17,12 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.9.2" +solana-program = "1.9.5" thiserror = "1.0" [dev-dependencies] -solana-program-test = "1.9.2" -solana-sdk = "1.9.2" +solana-program-test = "1.9.5" +solana-sdk = "1.9.5" [lib] crate-type = ["cdylib", "lib"] From 0b7c1c9fa0e29c30da0530b30ee229af65daa994 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 15 Feb 2022 14:20:14 +0100 Subject: [PATCH 156/335] token: Support both token programs in associated-token-account (#2904) * token: Support both token programs in associated-token-account * Rename spl-token -> spl-token-2022, spl-token-legacy -> spl-token * Use spl-token by default * Check mint in get_account_data_len * Add checks for either token program * Rebase fix * Update version comments in tests --- program/Cargo.toml | 1 + program/src/instruction.rs | 74 +++++++++++++++++++++ program/src/processor.rs | 132 +++++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+) diff --git a/program/Cargo.toml b/program/Cargo.toml index 76ee9f7..ed73a07 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -21,6 +21,7 @@ solana-program = "1.9.5" thiserror = "1.0" [dev-dependencies] +lazy_static = "1.4.0" solana-program-test = "1.9.5" solana-sdk = "1.9.5" diff --git a/program/src/instruction.rs b/program/src/instruction.rs index c5936cf..d548a99 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -409,6 +409,31 @@ pub enum TokenInstruction { /// The freeze authority/multisignature of the mint. freeze_authority: COption, }, + /// Gets the required size of an account for the given mint as a little-endian + /// `u64`. + /// + /// Return data can be fetched using `sol_get_return_data` and deserializing + /// the return data as a little-endian `u64`. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[]` The mint to calculate for + GetAccountDataSize, // typically, there's also data, but this program ignores it + /// Initialize the Immutable Owner extension for the given token account + /// + /// Fails if the account has already been initialized, so must be called before + /// `InitializeAccount`. + /// + /// No-ops in this version of the program, but is included for compatibility + /// with the Associated Token Account program. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// + /// Data expected by this instruction: + /// None + InitializeImmutableOwner, } impl TokenInstruction { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). @@ -529,6 +554,8 @@ impl TokenInstruction { decimals, } } + 21 => Self::GetAccountDataSize, + 22 => Self::InitializeImmutableOwner, _ => return Err(TokenError::InvalidInstruction.into()), }) } @@ -625,6 +652,12 @@ impl TokenInstruction { buf.extend_from_slice(mint_authority.as_ref()); Self::pack_pubkey_option(freeze_authority, &mut buf); } + &Self::GetAccountDataSize => { + buf.push(21); + } + &Self::InitializeImmutableOwner => { + buf.push(22); + } }; buf } @@ -1298,6 +1331,33 @@ pub fn sync_native( }) } +/// Creates a `GetAccountDataSize` instruction +pub fn get_account_data_size( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, +) -> Result { + check_program_account(token_program_id)?; + + Ok(Instruction { + program_id: *token_program_id, + accounts: vec![AccountMeta::new(*mint_pubkey, false)], + data: TokenInstruction::GetAccountDataSize.pack(), + }) +} + +/// Creates a `InitializeImmutableOwner` instruction +pub fn initialize_immutable_owner( + token_program_id: &Pubkey, + account_pubkey: &Pubkey, +) -> Result { + check_program_account(token_program_id)?; + Ok(Instruction { + program_id: *token_program_id, + accounts: vec![AccountMeta::new(*account_pubkey, false)], + data: TokenInstruction::InitializeImmutableOwner.pack(), + }) +} + /// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS pub fn is_valid_signer_index(index: usize) -> bool { (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) @@ -1518,5 +1578,19 @@ mod test { assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); + + let check = TokenInstruction::GetAccountDataSize; + let packed = check.pack(); + let expect = vec![21u8]; + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::InitializeImmutableOwner; + let packed = check.pack(); + let expect = vec![22u8]; + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); } } diff --git a/program/src/processor.rs b/program/src/processor.rs index d0045a4..f404d4e 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -11,6 +11,7 @@ use solana_program::{ decode_error::DecodeError, entrypoint::ProgramResult, msg, + program::set_return_data, program_error::{PrintProgramError, ProgramError}, program_memory::{sol_memcmp, sol_memset}, program_option::COption, @@ -757,6 +758,32 @@ impl Processor { Ok(()) } + /// Processes a [GetAccountDataSize](enum.TokenInstruction.html) instruction + pub fn process_get_account_data_size( + program_id: &Pubkey, + accounts: &[AccountInfo], + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + // make sure the mint is valid + let mint_info = next_account_info(account_info_iter)?; + Self::check_account_owner(program_id, mint_info)?; + let _ = Mint::unpack(&mint_info.data.borrow())?; + set_return_data(&Account::LEN.to_le_bytes()); + Ok(()) + } + + /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) instruction + pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let token_account_info = next_account_info(account_info_iter)?; + let account = Account::unpack_unchecked(&token_account_info.data.borrow())?; + if account.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } + msg!("Please upgrade to SPL Token 2022 for immutable owner support"); + Ok(()) + } + /// Processes an [Instruction](enum.Instruction.html). pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { let instruction = TokenInstruction::unpack(input)?; @@ -857,6 +884,14 @@ impl Processor { msg!("Instruction: SyncNative"); Self::process_sync_native(program_id, accounts) } + TokenInstruction::GetAccountDataSize => { + msg!("Instruction: GetAccountDataSize"); + Self::process_get_account_data_size(program_id, accounts) + } + TokenInstruction::InitializeImmutableOwner => { + msg!("Instruction: InitializeImmutableOwner"); + Self::process_initialize_immutable_owner(accounts) + } } } @@ -968,6 +1003,15 @@ mod tests { use solana_sdk::account::{ create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, }; + use std::sync::{Arc, RwLock}; + + lazy_static::lazy_static! { + static ref EXPECTED_DATA: Arc>> = Arc::new(RwLock::new(Vec::new())); + } + + fn set_expected_data(expected_data: Vec) { + *EXPECTED_DATA.write().unwrap() = expected_data; + } struct SyscallStubs {} impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs { @@ -1001,6 +1045,10 @@ mod tests { } solana_program::entrypoint::SUCCESS } + + fn sol_set_return_data(&self, data: &[u8]) { + assert_eq!(&*EXPECTED_DATA.write().unwrap(), data) + } } fn do_process_instruction( @@ -6355,4 +6403,88 @@ mod tests { ) ); } + + #[test] + fn test_get_account_data_size() { + // see integration tests for return-data validity + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mut rent_sysvar = rent_sysvar(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_key = Pubkey::new_unique(); + // fail if an invalid mint is passed in + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + get_account_data_size(&program_id, &mint_key).unwrap(), + vec![&mut mint_account], + ) + ); + + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data(Account::LEN.to_le_bytes().to_vec()); + do_process_instruction( + get_account_data_size(&program_id, &mint_key).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + } + + #[test] + fn test_initialize_immutable_owner() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // success initialize immutable + do_process_instruction( + initialize_immutable_owner(&program_id, &account_key).unwrap(), + vec![&mut account_account], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // fail post-init + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_immutable_owner(&program_id, &account_key).unwrap(), + vec![&mut account_account], + ) + ); + } } From 9f882ab2fb0ac6b3162106fb814abeb7bec309c6 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Tue, 15 Feb 2022 17:27:28 -0700 Subject: [PATCH 157/335] Initialize close_authority explicitly (#2919) --- program/src/processor.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/program/src/processor.rs b/program/src/processor.rs index f404d4e..eeee445 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -117,6 +117,7 @@ impl Processor { account.mint = *mint_info.key; account.owner = *owner; + account.close_authority = COption::None; account.delegate = COption::None; account.delegated_amount = 0; account.state = AccountState::Initialized; From 9d202dcc56a6d593e41f131c77439719d244234b Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 17 Feb 2022 16:25:57 -0700 Subject: [PATCH 158/335] Add token Amount/UiAmount conversion Instructions (#2928) * Add Amount/UiAmount conversion Instructions to spl-token * Use invalid-mint error in spl_token get_account_data_size * Add Amount/UiAmount conversion Instructions to spl-token-2022 --- program/Cargo.toml | 1 + program/src/instruction.rs | 99 +++++++++++++++- program/src/lib.rs | 49 ++++++++ program/src/processor.rs | 228 ++++++++++++++++++++++++++++++++++++- 4 files changed, 372 insertions(+), 5 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index ed73a07..2fe11c3 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -22,6 +22,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" +serial_test = "0.5.1" solana-program-test = "1.9.5" solana-sdk = "1.9.5" diff --git a/program/src/instruction.rs b/program/src/instruction.rs index d548a99..f3b22f1 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -19,7 +19,7 @@ pub const MAX_SIGNERS: usize = 11; /// Instructions supported by the token program. #[repr(C)] #[derive(Clone, Debug, PartialEq)] -pub enum TokenInstruction { +pub enum TokenInstruction<'a> { /// Initializes a new mint and optionally deposits all the newly minted /// tokens in an account. /// @@ -434,10 +434,38 @@ pub enum TokenInstruction { /// Data expected by this instruction: /// None InitializeImmutableOwner, + /// Convert an Amount of tokens to a UiAmount `string`, using the given mint. + /// In this version of the program, the mint can only specify the number of decimals. + /// + /// Fails on an invalid mint. + /// + /// Return data can be fetched using `sol_get_return_data` and deserialized with + /// `String::from_utf8`. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[]` The mint to calculate for + AmountToUiAmount { + /// The amount of tokens to reformat. + amount: u64, + }, + /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using the given mint. + /// In this version of the program, the mint can only specify the number of decimals. + /// + /// Return data can be fetched using `sol_get_return_data` and deserializing + /// the return data as a little-endian `u64`. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[]` The mint to calculate for + UiAmountToAmount { + /// The ui_amount of tokens to reformat. + ui_amount: &'a str, + }, } -impl TokenInstruction { +impl<'a> TokenInstruction<'a> { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). - pub fn unpack(input: &[u8]) -> Result { + pub fn unpack(input: &'a [u8]) -> Result { use TokenError::InvalidInstruction; let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?; @@ -556,6 +584,19 @@ impl TokenInstruction { } 21 => Self::GetAccountDataSize, 22 => Self::InitializeImmutableOwner, + 23 => { + let (amount, _rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + Self::AmountToUiAmount { amount } + } + 24 => { + let ui_amount = std::str::from_utf8(rest).map_err(|_| InvalidInstruction)?; + Self::UiAmountToAmount { ui_amount } + } _ => return Err(TokenError::InvalidInstruction.into()), }) } @@ -658,6 +699,14 @@ impl TokenInstruction { &Self::InitializeImmutableOwner => { buf.push(22); } + &Self::AmountToUiAmount { amount } => { + buf.push(23); + buf.extend_from_slice(&amount.to_le_bytes()); + } + Self::UiAmountToAmount { ui_amount } => { + buf.push(24); + buf.extend_from_slice(ui_amount.as_bytes()); + } }; buf } @@ -1358,6 +1407,36 @@ pub fn initialize_immutable_owner( }) } +/// Creates an `AmountToUiAmount` instruction +pub fn amount_to_ui_amount( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, + amount: u64, +) -> Result { + check_program_account(token_program_id)?; + + Ok(Instruction { + program_id: *token_program_id, + accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], + data: TokenInstruction::AmountToUiAmount { amount }.pack(), + }) +} + +/// Creates a `UiAmountToAmount` instruction +pub fn ui_amount_to_amount( + token_program_id: &Pubkey, + mint_pubkey: &Pubkey, + ui_amount: &str, +) -> Result { + check_program_account(token_program_id)?; + + Ok(Instruction { + program_id: *token_program_id, + accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], + data: TokenInstruction::UiAmountToAmount { ui_amount }.pack(), + }) +} + /// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS pub fn is_valid_signer_index(index: usize) -> bool { (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) @@ -1592,5 +1671,19 @@ mod test { assert_eq!(packed, expect); let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); + + let check = TokenInstruction::AmountToUiAmount { amount: 42 }; + let packed = check.pack(); + let expect = vec![23u8, 42, 0, 0, 0, 0, 0, 0, 0]; + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); + + let check = TokenInstruction::UiAmountToAmount { ui_amount: "0.42" }; + let packed = check.pack(); + let expect = vec![24u8, 48, 46, 52, 50]; + assert_eq!(packed, expect); + let unpacked = TokenInstruction::unpack(&expect).unwrap(); + assert_eq!(unpacked, check); } } diff --git a/program/src/lib.rs b/program/src/lib.rs index 4dda68d..2252ac1 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -27,6 +27,55 @@ pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { amount as f64 / 10_usize.pow(decimals as u32) as f64 } +/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { + let decimals = decimals as usize; + if decimals > 0 { + // Left-pad zeros to decimals + 1, so we at least have an integer zero + let mut s = format!("{:01$}", amount, decimals + 1); + // Add the decimal point (Sorry, "," locales!) + s.insert(s.len() - decimals, '.'); + s + } else { + amount.to_string() + } +} + +/// Convert a raw amount to its UI representation using the given decimals field +/// Excess zeroes or unneeded decimal point are trimmed. +pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { + let mut s = amount_to_ui_amount_string(amount, decimals); + if decimals > 0 { + let zeros_trimmed = s.trim_end_matches('0'); + s = zeros_trimmed.trim_end_matches('.').to_string(); + } + s +} + +/// Try to convert a UI represenation of a token amount to its raw amount using the given decimals +/// field +pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { + let decimals = decimals as usize; + let mut parts = ui_amount.split('.'); + let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at least len == 1 + let after_decimal = parts.next().unwrap_or(""); + let after_decimal = after_decimal.trim_end_matches('0'); + if (amount_str.is_empty() && after_decimal.is_empty()) + || parts.next().is_some() + || after_decimal.len() > decimals + { + return Err(ProgramError::InvalidArgument); + } + + amount_str.push_str(after_decimal); + for _ in 0..decimals.saturating_sub(after_decimal.len()) { + amount_str.push('0'); + } + amount_str + .parse::() + .map_err(|_| ProgramError::InvalidArgument) +} + solana_program::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); /// Checks that the supplied program ID is the correct one for SPL-token diff --git a/program/src/processor.rs b/program/src/processor.rs index eeee445..4dded86 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1,9 +1,11 @@ //! Program state processor use crate::{ + amount_to_ui_amount_string_trimmed, error::TokenError, instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, state::{Account, AccountState, Mint, Multisig}, + try_ui_amount_into_amount, }; use num_traits::FromPrimitive; use solana_program::{ @@ -768,7 +770,8 @@ impl Processor { // make sure the mint is valid let mint_info = next_account_info(account_info_iter)?; Self::check_account_owner(program_id, mint_info)?; - let _ = Mint::unpack(&mint_info.data.borrow())?; + let _ = Mint::unpack(&mint_info.data.borrow()) + .map_err(|_| Into::::into(TokenError::InvalidMint))?; set_return_data(&Account::LEN.to_le_bytes()); Ok(()) } @@ -785,6 +788,42 @@ impl Processor { Ok(()) } + /// Processes an [AmountToUiAmount](enum.TokenInstruction.html) instruction + pub fn process_amount_to_ui_amount( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let mint_info = next_account_info(account_info_iter)?; + Self::check_account_owner(program_id, mint_info)?; + + let mint = Mint::unpack(&mint_info.data.borrow_mut()) + .map_err(|_| Into::::into(TokenError::InvalidMint))?; + let ui_amount = amount_to_ui_amount_string_trimmed(amount, mint.decimals); + + set_return_data(&ui_amount.into_bytes()); + Ok(()) + } + + /// Processes an [AmountToUiAmount](enum.TokenInstruction.html) instruction + pub fn process_ui_amount_to_amount( + program_id: &Pubkey, + accounts: &[AccountInfo], + ui_amount: &str, + ) -> ProgramResult { + let account_info_iter = &mut accounts.iter(); + let mint_info = next_account_info(account_info_iter)?; + Self::check_account_owner(program_id, mint_info)?; + + let mint = Mint::unpack(&mint_info.data.borrow_mut()) + .map_err(|_| Into::::into(TokenError::InvalidMint))?; + let amount = try_ui_amount_into_amount(ui_amount.to_string(), mint.decimals)?; + + set_return_data(&amount.to_le_bytes()); + Ok(()) + } + /// Processes an [Instruction](enum.Instruction.html). pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { let instruction = TokenInstruction::unpack(input)?; @@ -893,6 +932,14 @@ impl Processor { msg!("Instruction: InitializeImmutableOwner"); Self::process_initialize_immutable_owner(accounts) } + TokenInstruction::AmountToUiAmount { amount } => { + msg!("Instruction: AmountToUiAmount"); + Self::process_amount_to_ui_amount(program_id, accounts, amount) + } + TokenInstruction::UiAmountToAmount { ui_amount } => { + msg!("Instruction: UiAmountToAmount"); + Self::process_ui_amount_to_amount(program_id, accounts, ui_amount) + } } } @@ -997,6 +1044,7 @@ impl PrintProgramError for TokenError { mod tests { use super::*; use crate::instruction::*; + use serial_test::serial; use solana_program::{ account_info::IntoAccountInfo, clock::Epoch, instruction::Instruction, program_error, sysvar::rent, @@ -6406,6 +6454,7 @@ mod tests { } #[test] + #[serial] fn test_get_account_data_size() { // see integration tests for return-data validity let program_id = crate::id(); @@ -6416,7 +6465,7 @@ mod tests { let mint_key = Pubkey::new_unique(); // fail if an invalid mint is passed in assert_eq!( - Err(ProgramError::UninitializedAccount), + Err(TokenError::InvalidMint.into()), do_process_instruction( get_account_data_size(&program_id, &mint_key).unwrap(), vec![&mut mint_account], @@ -6488,4 +6537,179 @@ mod tests { ) ); } + + #[test] + #[serial] + fn test_amount_to_ui_amount() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // fail if an invalid mint is passed in + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), + vec![&mut mint_account], + ) + ); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data("0.23".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 23).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("1.1".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("42".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 4200).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("0".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 0).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + } + + #[test] + #[serial] + fn test_ui_amount_to_amount() { + let program_id = crate::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // fail if an invalid mint is passed in + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), + vec![&mut mint_account], + ) + ); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data(23u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.23").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.20").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.2000").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, ".20").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(110u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(110u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "1.10").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(4200u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "42").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(4200u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "42.").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(0u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // fail if invalid ui_amount passed in + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, ".").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.111").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.t").unwrap(), + vec![&mut mint_account], + ) + ); + } } From 53bf3de9898b1596faa4a31d0f7d89fc4759f30b Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 23 Feb 2022 16:20:55 -0700 Subject: [PATCH 159/335] Bump solana to v1.9.9 (#2902) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 2fe11c3..87ba833 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,14 +17,14 @@ arrayref = "0.3.6" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.9.5" +solana-program = "1.9.9" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" serial_test = "0.5.1" -solana-program-test = "1.9.5" -solana-sdk = "1.9.5" +solana-program-test = "1.9.9" +solana-sdk = "1.9.9" [lib] crate-type = ["cdylib", "lib"] From 05c4d939e33f8b616263d5e971e2874369a0991c Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 24 Feb 2022 16:46:47 -0700 Subject: [PATCH 160/335] Add comment (#2954) --- program/src/instruction.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index f3b22f1..37f3ea7 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -462,6 +462,9 @@ pub enum TokenInstruction<'a> { /// The ui_amount of tokens to reformat. ui_amount: &'a str, }, + // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the + // latter remains a superset of this instruction set. New variants also need to be added to + // token/js/src/instructions/types.ts to maintain @solana/spl-token compatability } impl<'a> TokenInstruction<'a> { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). From c8190f3fb31cce999e375d7e78123acadd8ae439 Mon Sep 17 00:00:00 2001 From: Lijun Wang <83639177+lijunwangs@users.noreply.github.com> Date: Wed, 2 Mar 2022 11:34:55 -0800 Subject: [PATCH 161/335] Support unpacking token accounts fields partially (#2970) * Support unpacking token accounts fields partially Co-authored-by: Tyera Eulberg --- program/Cargo.toml | 1 + program/src/state.rs | 88 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 87ba833..8e81fc6 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,6 +14,7 @@ test-bpf = [] [dependencies] arrayref = "0.3.6" +bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" diff --git a/program/src/state.rs b/program/src/state.rs index 71f0d40..bd53434 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -7,7 +7,7 @@ use solana_program::{ program_error::ProgramError, program_option::COption, program_pack::{IsInitialized, Pack, Sealed}, - pubkey::Pubkey, + pubkey::{Pubkey, PUBKEY_BYTES}, }; /// Mint data. @@ -287,6 +287,56 @@ fn unpack_coption_u64(src: &[u8; 12]) -> Result, ProgramError> { } } +const SPL_TOKEN_ACCOUNT_MINT_OFFSET: usize = 0; +const SPL_TOKEN_ACCOUNT_OWNER_OFFSET: usize = 32; + +/// A trait for token Account structs to enable efficiently unpacking various fields +/// without unpacking the complete state. +pub trait GenericTokenAccount { + /// Check if the account data is a valid token account + fn valid_account_data(account_data: &[u8]) -> bool; + + /// Call after account length has already been verified to unpack the account owner + fn unpack_account_owner_unchecked(account_data: &[u8]) -> &Pubkey { + Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_OWNER_OFFSET) + } + + /// Call after account length has already been verified to unpack the account mint + fn unpack_account_mint_unchecked(account_data: &[u8]) -> &Pubkey { + Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_MINT_OFFSET) + } + + /// Call after account length has already been verified to unpack a Pubkey at + /// the specified offset. Panics if `account_data.len()` is less than `PUBKEY_BYTES` + fn unpack_pubkey_unchecked(account_data: &[u8], offset: usize) -> &Pubkey { + bytemuck::from_bytes(&account_data[offset..offset + PUBKEY_BYTES]) + } + + /// Unpacks an account's owner from opaque account data. + fn unpack_account_owner(account_data: &[u8]) -> Option<&Pubkey> { + if Self::valid_account_data(account_data) { + Some(Self::unpack_account_owner_unchecked(account_data)) + } else { + None + } + } + + /// Unpacks an account's mint from opaque account data. + fn unpack_account_mint(account_data: &[u8]) -> Option<&Pubkey> { + if Self::valid_account_data(account_data) { + Some(Self::unpack_account_mint_unchecked(account_data)) + } else { + None + } + } +} + +impl GenericTokenAccount for Account { + fn valid_account_data(account_data: &[u8]) -> bool { + account_data.len() == Account::LEN + } +} + #[cfg(test)] mod tests { use super::*; @@ -360,4 +410,40 @@ mod tests { let result = unpack_coption_u64(&src).unwrap_err(); assert_eq!(result, ProgramError::InvalidAccountData); } + + #[test] + fn test_unpack_token_owner() { + // Account data length < Account::LEN, unpack will not return a key + let src: [u8; 12] = [0; 12]; + let result = Account::unpack_account_owner(&src); + assert_eq!(result, Option::None); + + // The right account data size, unpack will return some key + let src: [u8; Account::LEN] = [0; Account::LEN]; + let result = Account::unpack_account_owner(&src); + assert!(result.is_some()); + + // Account data length > account data size, unpack will not return a key + let src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; + let result = Account::unpack_account_owner(&src); + assert_eq!(result, Option::None); + } + + #[test] + fn test_unpack_token_mint() { + // Account data length < Account::LEN, unpack will not return a key + let src: [u8; 12] = [0; 12]; + let result = Account::unpack_account_mint(&src); + assert_eq!(result, Option::None); + + // The right account data size, unpack will return some key + let src: [u8; Account::LEN] = [0; Account::LEN]; + let result = Account::unpack_account_mint(&src); + assert!(result.is_some()); + + // Account data length > account data size, unpack will not return a key + let src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; + let result = Account::unpack_account_mint(&src); + assert_eq!(result, Option::None); + } } From f92101357a30c3d9470a03e8c5efd271064a455a Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 3 Mar 2022 12:34:17 -0700 Subject: [PATCH 162/335] Spell out destination (#2977) --- program/src/processor.rs | 51 +++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 4dded86..7c0ce9c 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -235,19 +235,19 @@ impl Processor { None }; - let dest_account_info = next_account_info(account_info_iter)?; + let destination_account_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; let mut source_account = Account::unpack(&source_account_info.data.borrow())?; - let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; + let mut destination_account = Account::unpack(&destination_account_info.data.borrow())?; - if source_account.is_frozen() || dest_account.is_frozen() { + if source_account.is_frozen() || destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } if source_account.amount < amount { return Err(TokenError::InsufficientFunds.into()); } - if !Self::cmp_pubkeys(&source_account.mint, &dest_account.mint) { + if !Self::cmp_pubkeys(&source_account.mint, &destination_account.mint) { return Err(TokenError::MintMismatch.into()); } @@ -262,7 +262,8 @@ impl Processor { } } - let self_transfer = Self::cmp_pubkeys(source_account_info.key, dest_account_info.key); + let self_transfer = + Self::cmp_pubkeys(source_account_info.key, destination_account_info.key); match source_account.delegate { COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => { @@ -295,7 +296,7 @@ impl Processor { if self_transfer || amount == 0 { Self::check_account_owner(program_id, source_account_info)?; - Self::check_account_owner(program_id, dest_account_info)?; + Self::check_account_owner(program_id, destination_account_info)?; } // This check MUST occur just before the amounts are manipulated @@ -308,7 +309,7 @@ impl Processor { .amount .checked_sub(amount) .ok_or(TokenError::Overflow)?; - dest_account.amount = dest_account + destination_account.amount = destination_account .amount .checked_add(amount) .ok_or(TokenError::Overflow)?; @@ -319,14 +320,17 @@ impl Processor { .checked_sub(amount) .ok_or(TokenError::Overflow)?; - let dest_starting_lamports = dest_account_info.lamports(); - **dest_account_info.lamports.borrow_mut() = dest_starting_lamports + let destination_starting_lamports = destination_account_info.lamports(); + **destination_account_info.lamports.borrow_mut() = destination_starting_lamports .checked_add(amount) .ok_or(TokenError::Overflow)?; } Account::pack(source_account, &mut source_account_info.data.borrow_mut())?; - Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?; + Account::pack( + destination_account, + &mut destination_account_info.data.borrow_mut(), + )?; Ok(()) } @@ -517,18 +521,18 @@ impl Processor { ) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let mint_info = next_account_info(account_info_iter)?; - let dest_account_info = next_account_info(account_info_iter)?; + let destination_account_info = next_account_info(account_info_iter)?; let owner_info = next_account_info(account_info_iter)?; - let mut dest_account = Account::unpack(&dest_account_info.data.borrow())?; - if dest_account.is_frozen() { + let mut destination_account = Account::unpack(&destination_account_info.data.borrow())?; + if destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } - if dest_account.is_native() { + if destination_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } - if !Self::cmp_pubkeys(mint_info.key, &dest_account.mint) { + if !Self::cmp_pubkeys(mint_info.key, &destination_account.mint) { return Err(TokenError::MintMismatch.into()); } @@ -551,10 +555,10 @@ impl Processor { if amount == 0 { Self::check_account_owner(program_id, mint_info)?; - Self::check_account_owner(program_id, dest_account_info)?; + Self::check_account_owner(program_id, destination_account_info)?; } - dest_account.amount = dest_account + destination_account.amount = destination_account .amount .checked_add(amount) .ok_or(TokenError::Overflow)?; @@ -564,7 +568,10 @@ impl Processor { .checked_add(amount) .ok_or(TokenError::Overflow)?; - Account::pack(dest_account, &mut dest_account_info.data.borrow_mut())?; + Account::pack( + destination_account, + &mut destination_account_info.data.borrow_mut(), + )?; Mint::pack(mint, &mut mint_info.data.borrow_mut())?; Ok(()) @@ -657,10 +664,10 @@ impl Processor { pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let source_account_info = next_account_info(account_info_iter)?; - let dest_account_info = next_account_info(account_info_iter)?; + let destination_account_info = next_account_info(account_info_iter)?; let authority_info = next_account_info(account_info_iter)?; - if Self::cmp_pubkeys(source_account_info.key, dest_account_info.key) { + if Self::cmp_pubkeys(source_account_info.key, destination_account_info.key) { return Err(ProgramError::InvalidAccountData); } @@ -679,8 +686,8 @@ impl Processor { account_info_iter.as_slice(), )?; - let dest_starting_lamports = dest_account_info.lamports(); - **dest_account_info.lamports.borrow_mut() = dest_starting_lamports + let destination_starting_lamports = destination_account_info.lamports(); + **destination_account_info.lamports.borrow_mut() = destination_starting_lamports .checked_add(source_account_info.lamports()) .ok_or(TokenError::Overflow)?; From 2fbf73a4b45f2f1c8d73eb54de3b0f7b4fe018ae Mon Sep 17 00:00:00 2001 From: Lijun Wang <83639177+lijunwangs@users.noreply.github.com> Date: Wed, 9 Mar 2022 16:53:48 -0800 Subject: [PATCH 163/335] Added checks if a token account is initialized when checking validity (#2986) * Added checks if an account is initialized when checking validity --- program/src/state.rs | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/program/src/state.rs b/program/src/state.rs index bd53434..e9e57ad 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -331,9 +331,21 @@ pub trait GenericTokenAccount { } } +/// The offset of state field in Account's C representation +pub const ACCOUNT_INITIALIZED_INDEX: usize = 108; + +/// Check if the account data buffer represents an initialized account. +/// This is checking the `state` (AccountState) field of an Account object. +pub fn is_initialized_account(account_data: &[u8]) -> bool { + *account_data + .get(ACCOUNT_INITIALIZED_INDEX) + .unwrap_or(&(AccountState::Uninitialized as u8)) + != AccountState::Uninitialized as u8 +} + impl GenericTokenAccount for Account { fn valid_account_data(account_data: &[u8]) -> bool { - account_data.len() == Account::LEN + account_data.len() == Account::LEN && is_initialized_account(account_data) } } @@ -418,11 +430,22 @@ mod tests { let result = Account::unpack_account_owner(&src); assert_eq!(result, Option::None); - // The right account data size, unpack will return some key - let src: [u8; Account::LEN] = [0; Account::LEN]; + // The right account data size and intialized, unpack will return some key + let mut src: [u8; Account::LEN] = [0; Account::LEN]; + src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; let result = Account::unpack_account_owner(&src); assert!(result.is_some()); + // The right account data size and frozen, unpack will return some key + src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Frozen as u8; + let result = Account::unpack_account_owner(&src); + assert!(result.is_some()); + + // The right account data size and uninitialized, unpack will return None + src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8; + let result = Account::unpack_account_mint(&src); + assert_eq!(result, Option::None); + // Account data length > account data size, unpack will not return a key let src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; let result = Account::unpack_account_owner(&src); @@ -436,11 +459,22 @@ mod tests { let result = Account::unpack_account_mint(&src); assert_eq!(result, Option::None); - // The right account data size, unpack will return some key - let src: [u8; Account::LEN] = [0; Account::LEN]; + // The right account data size and initialized, unpack will return some key + let mut src: [u8; Account::LEN] = [0; Account::LEN]; + src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; + let result = Account::unpack_account_mint(&src); + assert!(result.is_some()); + + // The right account data size and frozen, unpack will return some key + src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Frozen as u8; let result = Account::unpack_account_mint(&src); assert!(result.is_some()); + // The right account data size and uninitialized, unpack will return None + src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Uninitialized as u8; + let result = Account::unpack_account_mint(&src); + assert_eq!(result, Option::None); + // Account data length > account data size, unpack will not return a key let src: [u8; Account::LEN + 5] = [0; Account::LEN + 5]; let result = Account::unpack_account_mint(&src); From e2d0291eeb5976aee7b364a65b5eb57e2327093f Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 9 Mar 2022 19:31:39 -0700 Subject: [PATCH 164/335] token-2022: Allow anyone to burn/close an Account owned by the system program or the incinerator (#2890) * Allow anyone to burn and close token Accounts owned by the system program and the incinerator * Require rent from incinerator/system-owned token accounts be burnt when accounts closed * Add support to OG program --- program/src/processor.rs | 321 +++++++++++++++++++++++++++++++++++---- program/src/state.rs | 5 + 2 files changed, 298 insertions(+), 28 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 7c0ce9c..ac8e30a 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -612,32 +612,34 @@ impl Processor { } } - match source_account.delegate { - COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => { - Self::validate_owner( + if !source_account.is_owned_by_system_program_or_incinerator() { + match source_account.delegate { + COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => { + Self::validate_owner( + program_id, + delegate, + authority_info, + account_info_iter.as_slice(), + )?; + + if source_account.delegated_amount < amount { + return Err(TokenError::InsufficientFunds.into()); + } + source_account.delegated_amount = source_account + .delegated_amount + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + if source_account.delegated_amount == 0 { + source_account.delegate = COption::None; + } + } + _ => Self::validate_owner( program_id, - delegate, + &source_account.owner, authority_info, account_info_iter.as_slice(), - )?; - - if source_account.delegated_amount < amount { - return Err(TokenError::InsufficientFunds.into()); - } - source_account.delegated_amount = source_account - .delegated_amount - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - if source_account.delegated_amount == 0 { - source_account.delegate = COption::None; - } + )?, } - _ => Self::validate_owner( - program_id, - &source_account.owner, - authority_info, - account_info_iter.as_slice(), - )?, } if amount == 0 { @@ -679,12 +681,16 @@ impl Processor { let authority = source_account .close_authority .unwrap_or(source_account.owner); - Self::validate_owner( - program_id, - &authority, - authority_info, - account_info_iter.as_slice(), - )?; + if !source_account.is_owned_by_system_program_or_incinerator() { + Self::validate_owner( + program_id, + &authority, + authority_info, + account_info_iter.as_slice(), + )?; + } else if !solana_program::incinerator::check_id(destination_account_info.key) { + return Err(ProgramError::InvalidAccountData); + } let destination_starting_lamports = destination_account_info.lamports(); **destination_account_info.lamports.borrow_mut() = destination_starting_lamports @@ -4575,6 +4581,265 @@ mod tests { ); } + #[test] + fn test_burn_and_close_system_and_incinerator_tokens() { + let program_id = crate::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let incinerator_account_key = Pubkey::new_unique(); + let mut incinerator_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let system_account_key = Pubkey::new_unique(); + let mut system_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let recipient_key = Pubkey::new_unique(); + let mut recipient_account = SolanaAccount::default(); + let mut mock_incinerator_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + + // create new mint + do_process_instruction( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account], + ) + .unwrap(); + + // create incinerator- and system-owned accounts + do_process_instruction( + initialize_account3( + &program_id, + &incinerator_account_key, + &mint_key, + &solana_program::incinerator::id(), + ) + .unwrap(), + vec![&mut incinerator_account, &mut mint_account], + ) + .unwrap(); + do_process_instruction( + initialize_account3( + &program_id, + &system_account_key, + &mint_key, + &solana_program::system_program::id(), + ) + .unwrap(), + vec![&mut system_account, &mut mint_account], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // transfer half to incinerator, half to system program + do_process_instruction( + transfer( + &program_id, + &account_key, + &incinerator_account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &system_account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut system_account, + &mut owner_account, + ], + ) + .unwrap(); + + // close with balance fails + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + ); + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut system_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + ); + + // anyone can burn + do_process_instruction( + burn( + &program_id, + &incinerator_account_key, + &mint_key, + &recipient_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mint_account, + &mut recipient_account, + ], + ) + .unwrap(); + do_process_instruction( + burn( + &program_id, + &system_account_key, + &mint_key, + &recipient_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut system_account, + &mut mint_account, + &mut recipient_account, + ], + ) + .unwrap(); + + // closing fails if destination is not the incinerator + assert_eq!( + Err(ProgramError::InvalidAccountData), + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &recipient_key, + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut recipient_account, + &mut owner_account, + ], + ) + ); + assert_eq!( + Err(ProgramError::InvalidAccountData), + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &recipient_key, + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut system_account, + &mut recipient_account, + &mut owner_account, + ], + ) + ); + + // closing succeeds with incinerator recipient + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[], + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); + + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[], + ) + .unwrap(), + vec![ + &mut system_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); + } + #[test] fn test_multisig() { let program_id = crate::id(); diff --git a/program/src/state.rs b/program/src/state.rs index e9e57ad..6070141 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -113,6 +113,11 @@ impl Account { pub fn is_native(&self) -> bool { self.is_native.is_some() } + /// Checks if a token Account's owner is the system_program or the incinerator + pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { + solana_program::system_program::check_id(&self.owner) + || solana_program::incinerator::check_id(&self.owner) + } } impl Sealed for Account {} impl IsInitialized for Account { From 1858e226158e9365921ae89b0f5433bc74ef1225 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Mon, 11 Apr 2022 22:25:27 +0200 Subject: [PATCH 165/335] Upgrade crates to 1.10.8 (#3076) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 8e81fc6..ded6b86 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,14 +18,14 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.9.9" +solana-program = "1.10.8" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" serial_test = "0.5.1" -solana-program-test = "1.9.9" -solana-sdk = "1.9.9" +solana-program-test = "1.10.8" +solana-sdk = "1.10.8" [lib] crate-type = ["cdylib", "lib"] From ac6d8152994b897a2b6c8ca8d79aeb2f82653ff1 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 22 Apr 2022 23:55:18 +0200 Subject: [PATCH 166/335] token-2022: Add compatibility test for instructions (#3106) --- program/src/instruction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 37f3ea7..c69c7bb 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -1392,7 +1392,7 @@ pub fn get_account_data_size( Ok(Instruction { program_id: *token_program_id, - accounts: vec![AccountMeta::new(*mint_pubkey, false)], + accounts: vec![AccountMeta::new_readonly(*mint_pubkey, false)], data: TokenInstruction::GetAccountDataSize.pack(), }) } From 1b3cf8ff3e180af4cc57d2da84afc2a009ef152d Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Tue, 26 Apr 2022 14:15:26 -0400 Subject: [PATCH 167/335] Bump token-2022 (#3113) * Bump token-2022 * Bump solana dependencies --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index ded6b86..4c53835 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,14 +18,14 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.10.8" +solana-program = "1.10.10" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" serial_test = "0.5.1" -solana-program-test = "1.10.8" -solana-sdk = "1.10.8" +solana-program-test = "1.10.10" +solana-sdk = "1.10.10" [lib] crate-type = ["cdylib", "lib"] From 0492788f69157c1a14bfc381c96a095eafcfe367 Mon Sep 17 00:00:00 2001 From: Dmitri Makarov Date: Tue, 17 May 2022 11:27:30 -0700 Subject: [PATCH 168/335] Bump solana to v1.10.15 (#3176) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 4c53835..dacf748 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,14 +18,14 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.10.10" +solana-program = "1.10.15" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" serial_test = "0.5.1" -solana-program-test = "1.10.10" -solana-sdk = "1.10.10" +solana-program-test = "1.10.15" +solana-sdk = "1.10.15" [lib] crate-type = ["cdylib", "lib"] From 9027cc2791652f331f566b369841174033835829 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 1 Jul 2022 22:51:01 +0200 Subject: [PATCH 169/335] Update Solana crates to 1.10.29 (#3303) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index dacf748..fdf1ebe 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,14 +18,14 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.10.15" +solana-program = "1.10.29" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" serial_test = "0.5.1" -solana-program-test = "1.10.15" -solana-sdk = "1.10.15" +solana-program-test = "1.10.29" +solana-sdk = "1.10.29" [lib] crate-type = ["cdylib", "lib"] From 7fa6e2d63cb33408ea1bb77cb8c7899ac2d2cf07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Mal=C4=8Di=C4=87?= Date: Tue, 26 Jul 2022 12:59:37 +0100 Subject: [PATCH 170/335] Improve token error messages in token-swap (#3357) * Move PrintProgramError impls * Add wrapper function * Add PrintProgramError to use declaration --- program/src/error.rs | 54 +++++++++++++++++++++++++++++++++++++++- program/src/processor.rs | 53 ++++----------------------------------- 2 files changed, 58 insertions(+), 49 deletions(-) diff --git a/program/src/error.rs b/program/src/error.rs index ed3faed..454aa9e 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -1,7 +1,11 @@ //! Error types use num_derive::FromPrimitive; -use solana_program::{decode_error::DecodeError, program_error::ProgramError}; +use solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, +}; use thiserror::Error; /// Errors that may be returned by the Token program. @@ -85,3 +89,51 @@ impl DecodeError for TokenError { "TokenError" } } + +impl PrintProgramError for TokenError { + fn print(&self) + where + E: 'static + + std::error::Error + + DecodeError + + PrintProgramError + + num_traits::FromPrimitive, + { + match self { + TokenError::NotRentExempt => msg!("Error: Lamport balance below rent-exempt threshold"), + TokenError::InsufficientFunds => msg!("Error: insufficient funds"), + TokenError::InvalidMint => msg!("Error: Invalid Mint"), + TokenError::MintMismatch => msg!("Error: Account not associated with this Mint"), + TokenError::OwnerMismatch => msg!("Error: owner does not match"), + TokenError::FixedSupply => msg!("Error: the total supply of this token is fixed"), + TokenError::AlreadyInUse => msg!("Error: account or token already in use"), + TokenError::InvalidNumberOfProvidedSigners => { + msg!("Error: Invalid number of provided signers") + } + TokenError::InvalidNumberOfRequiredSigners => { + msg!("Error: Invalid number of required signers") + } + TokenError::UninitializedState => msg!("Error: State is uninitialized"), + TokenError::NativeNotSupported => { + msg!("Error: Instruction does not support native tokens") + } + TokenError::NonNativeHasBalance => { + msg!("Error: Non-native account can only be closed if its balance is zero") + } + TokenError::InvalidInstruction => msg!("Error: Invalid instruction"), + TokenError::InvalidState => msg!("Error: Invalid account state for operation"), + TokenError::Overflow => msg!("Error: Operation overflowed"), + TokenError::AuthorityTypeNotSupported => { + msg!("Error: Account does not support specified authority type") + } + TokenError::MintCannotFreeze => msg!("Error: This token mint cannot freeze accounts"), + TokenError::AccountFrozen => msg!("Error: Account is frozen"), + TokenError::MintDecimalsMismatch => { + msg!("Error: decimals different from the Mint decimals") + } + TokenError::NonNativeNotSupported => { + msg!("Error: Instruction does not support non-native tokens") + } + } + } +} diff --git a/program/src/processor.rs b/program/src/processor.rs index ac8e30a..e617709 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -7,14 +7,12 @@ use crate::{ state::{Account, AccountState, Mint, Multisig}, try_ui_amount_into_amount, }; -use num_traits::FromPrimitive; use solana_program::{ account_info::{next_account_info, AccountInfo}, - decode_error::DecodeError, entrypoint::ProgramResult, msg, program::set_return_data, - program_error::{PrintProgramError, ProgramError}, + program_error::ProgramError, program_memory::{sol_memcmp, sol_memset}, program_option::COption, program_pack::{IsInitialized, Pack}, @@ -1009,57 +1007,16 @@ impl Processor { } } -impl PrintProgramError for TokenError { - fn print(&self) - where - E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, - { - match self { - TokenError::NotRentExempt => msg!("Error: Lamport balance below rent-exempt threshold"), - TokenError::InsufficientFunds => msg!("Error: insufficient funds"), - TokenError::InvalidMint => msg!("Error: Invalid Mint"), - TokenError::MintMismatch => msg!("Error: Account not associated with this Mint"), - TokenError::OwnerMismatch => msg!("Error: owner does not match"), - TokenError::FixedSupply => msg!("Error: the total supply of this token is fixed"), - TokenError::AlreadyInUse => msg!("Error: account or token already in use"), - TokenError::InvalidNumberOfProvidedSigners => { - msg!("Error: Invalid number of provided signers") - } - TokenError::InvalidNumberOfRequiredSigners => { - msg!("Error: Invalid number of required signers") - } - TokenError::UninitializedState => msg!("Error: State is uninitialized"), - TokenError::NativeNotSupported => { - msg!("Error: Instruction does not support native tokens") - } - TokenError::NonNativeHasBalance => { - msg!("Error: Non-native account can only be closed if its balance is zero") - } - TokenError::InvalidInstruction => msg!("Error: Invalid instruction"), - TokenError::InvalidState => msg!("Error: Invalid account state for operation"), - TokenError::Overflow => msg!("Error: Operation overflowed"), - TokenError::AuthorityTypeNotSupported => { - msg!("Error: Account does not support specified authority type") - } - TokenError::MintCannotFreeze => msg!("Error: This token mint cannot freeze accounts"), - TokenError::AccountFrozen => msg!("Error: Account is frozen"), - TokenError::MintDecimalsMismatch => { - msg!("Error: decimals different from the Mint decimals") - } - TokenError::NonNativeNotSupported => { - msg!("Error: Instruction does not support non-native tokens") - } - } - } -} - #[cfg(test)] mod tests { use super::*; use crate::instruction::*; use serial_test::serial; use solana_program::{ - account_info::IntoAccountInfo, clock::Epoch, instruction::Instruction, program_error, + account_info::IntoAccountInfo, + clock::Epoch, + instruction::Instruction, + program_error::{self, PrintProgramError}, sysvar::rent, }; use solana_sdk::account::{ From 27895b0e3709f94cc021d96173e47c93f3e77227 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 27 Jul 2022 10:28:14 -0700 Subject: [PATCH 171/335] Bump solana crates to v1.10.33 (#3385) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index fdf1ebe..45166f9 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,14 +18,14 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.10.29" +solana-program = "1.10.33" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" serial_test = "0.5.1" -solana-program-test = "1.10.29" -solana-sdk = "1.10.29" +solana-program-test = "1.10.33" +solana-sdk = "1.10.33" [lib] crate-type = ["cdylib", "lib"] From c2546035de8ffe38d3e026b4b1b118ff39ffd1bb Mon Sep 17 00:00:00 2001 From: anatoly yakovenko Date: Tue, 2 Aug 2022 22:11:13 -0700 Subject: [PATCH 172/335] check that unpack is tolerant of small sizes (#3416) --- program/src/instruction.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index c69c7bb..7e70b80 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -519,6 +519,9 @@ impl<'a> TokenInstruction<'a> { 10 => Self::FreezeAccount, 11 => Self::ThawAccount, 12 => { + if rest.len() < 8 { + return Err(TokenError::InvalidInstruction.into()); + } let (amount, rest) = rest.split_at(8); let amount = amount .try_into() @@ -530,6 +533,9 @@ impl<'a> TokenInstruction<'a> { Self::TransferChecked { amount, decimals } } 13 => { + if rest.len() < 8 { + return Err(TokenError::InvalidInstruction.into()); + } let (amount, rest) = rest.split_at(8); let amount = amount .try_into() @@ -541,6 +547,9 @@ impl<'a> TokenInstruction<'a> { Self::ApproveChecked { amount, decimals } } 14 => { + if rest.len() < 8 { + return Err(TokenError::InvalidInstruction.into()); + } let (amount, rest) = rest.split_at(8); let amount = amount .try_into() @@ -552,6 +561,9 @@ impl<'a> TokenInstruction<'a> { Self::MintToChecked { amount, decimals } } 15 => { + if rest.len() < 8 { + return Err(TokenError::InvalidInstruction.into()); + } let (amount, rest) = rest.split_at(8); let amount = amount .try_into() @@ -588,6 +600,9 @@ impl<'a> TokenInstruction<'a> { 21 => Self::GetAccountDataSize, 22 => Self::InitializeImmutableOwner, 23 => { + if rest.len() < 8 { + return Err(TokenError::InvalidInstruction.into()); + } let (amount, _rest) = rest.split_at(8); let amount = amount .try_into() @@ -1689,4 +1704,12 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); } + + #[test] + fn test_instruction_unpack_panic() { + for i in 0..255u8 { + let expect = Vec::from([i, 1, 0, 0, 0, 0, 0, 0, 0, 2]); + _ = TokenInstruction::unpack(&expect[0..2]); + } + } } From 4d20c24aa00df755da9f5ca1916f99e0425bdc63 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 3 Aug 2022 00:24:38 -0700 Subject: [PATCH 173/335] Bump spl-token (#3418) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 45166f9..5013edc 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.3.0" +version = "3.3.1" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From fe4bbbcc05156185e8b9b25bbc41f0fdbbc43223 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 3 Aug 2022 00:44:55 -0700 Subject: [PATCH 174/335] Refactor unpack and make test more robust (#3417) * Refactor hasty fix to match token-2022 * Make test exhaustive * cargo fmt Co-authored-by: Michael Vines --- program/src/instruction.rs | 82 +++++++++++++------------------------- 1 file changed, 27 insertions(+), 55 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 7e70b80..4a34e78 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -15,6 +15,8 @@ use std::mem::size_of; pub const MIN_SIGNERS: usize = 1; /// Maximum number of multisignature signers (max N) pub const MAX_SIGNERS: usize = 11; +/// Serialized length of a u64, for unpacking +const U64_BYTES: usize = 8; /// Instructions supported by the token program. #[repr(C)] @@ -519,59 +521,19 @@ impl<'a> TokenInstruction<'a> { 10 => Self::FreezeAccount, 11 => Self::ThawAccount, 12 => { - if rest.len() < 8 { - return Err(TokenError::InvalidInstruction.into()); - } - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - + let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; Self::TransferChecked { amount, decimals } } 13 => { - if rest.len() < 8 { - return Err(TokenError::InvalidInstruction.into()); - } - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - + let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; Self::ApproveChecked { amount, decimals } } 14 => { - if rest.len() < 8 { - return Err(TokenError::InvalidInstruction.into()); - } - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - + let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; Self::MintToChecked { amount, decimals } } 15 => { - if rest.len() < 8 { - return Err(TokenError::InvalidInstruction.into()); - } - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - + let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; Self::BurnChecked { amount, decimals } } 16 => { @@ -600,15 +562,7 @@ impl<'a> TokenInstruction<'a> { 21 => Self::GetAccountDataSize, 22 => Self::InitializeImmutableOwner, 23 => { - if rest.len() < 8 { - return Err(TokenError::InvalidInstruction.into()); - } - let (amount, _rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; + let (amount, _rest) = Self::unpack_u64(rest)?; Self::AmountToUiAmount { amount } } 24 => { @@ -760,6 +714,21 @@ impl<'a> TokenInstruction<'a> { COption::None => buf.push(0), } } + + fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> { + let value = input + .get(..U64_BYTES) + .and_then(|slice| slice.try_into().ok()) + .map(u64::from_le_bytes) + .ok_or(TokenError::InvalidInstruction)?; + Ok((value, &input[U64_BYTES..])) + } + + fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> { + let (amount, rest) = Self::unpack_u64(input)?; + let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?; + Ok((amount, decimals, rest)) + } } /// Specifies the authority type for SetAuthority instructions @@ -1708,8 +1677,11 @@ mod test { #[test] fn test_instruction_unpack_panic() { for i in 0..255u8 { - let expect = Vec::from([i, 1, 0, 0, 0, 0, 0, 0, 0, 2]); - _ = TokenInstruction::unpack(&expect[0..2]); + for j in 1..10 { + let mut data = vec![0; j]; + data[0] = i; + let _no_panic = TokenInstruction::unpack(&data); + } } } } From 7b318065ca137c30d384ae062f7b7799440820bf Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Wed, 3 Aug 2022 20:01:08 +0200 Subject: [PATCH 175/335] token[-2022]: Add proptest for unpacking (#3421) --- program/Cargo.toml | 1 + program/src/instruction.rs | 17 ++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 5013edc..481319e 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -23,6 +23,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" +proptest = "1.0" serial_test = "0.5.1" solana-program-test = "1.10.33" solana-sdk = "1.10.33" diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 4a34e78..d31c118 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -1431,7 +1431,7 @@ pub fn is_valid_signer_index(index: usize) -> bool { #[cfg(test)] mod test { - use super::*; + use {super::*, proptest::prelude::*}; #[test] fn test_instruction_packing() { @@ -1674,14 +1674,13 @@ mod test { assert_eq!(unpacked, check); } - #[test] - fn test_instruction_unpack_panic() { - for i in 0..255u8 { - for j in 1..10 { - let mut data = vec![0; j]; - data[0] = i; - let _no_panic = TokenInstruction::unpack(&data); - } + proptest! { + #![proptest_config(ProptestConfig::with_cases(1024))] + #[test] + fn test_instruction_unpack_panic( + data in prop::collection::vec(any::(), 0..255) + ) { + let _no_panic = TokenInstruction::unpack(&data); } } } From 3a887bf1236037a3399901b9a9765ca1f16f4146 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Wed, 3 Aug 2022 23:49:36 +0200 Subject: [PATCH 176/335] token: Reassign and reallocate accounts on close (#3415) * token: Reassign and reallocate accounts on close * Revert "Refactor unpack and make test more robust (#3417)" This reverts commit 3cd0c9a82209eaf445662c00122188155594ad4a. * Revert "check that unpack is tolerant of small sizes (#3416)" This reverts commit c202d51918c994230fc71f9b8829a7f7300d5d12. * Also revert 842d4bfad96329968121d0460403268fa73ffe4a --- program/src/instruction.rs | 72 ++++++------ program/src/processor.rs | 25 +++- program/tests/close_account.rs | 202 +++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+), 36 deletions(-) create mode 100644 program/tests/close_account.rs diff --git a/program/src/instruction.rs b/program/src/instruction.rs index d31c118..c69c7bb 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -15,8 +15,6 @@ use std::mem::size_of; pub const MIN_SIGNERS: usize = 1; /// Maximum number of multisignature signers (max N) pub const MAX_SIGNERS: usize = 11; -/// Serialized length of a u64, for unpacking -const U64_BYTES: usize = 8; /// Instructions supported by the token program. #[repr(C)] @@ -521,19 +519,47 @@ impl<'a> TokenInstruction<'a> { 10 => Self::FreezeAccount, 11 => Self::ThawAccount, 12 => { - let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; + let (amount, rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; + Self::TransferChecked { amount, decimals } } 13 => { - let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; + let (amount, rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; + Self::ApproveChecked { amount, decimals } } 14 => { - let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; + let (amount, rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; + Self::MintToChecked { amount, decimals } } 15 => { - let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; + let (amount, rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; + let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; + Self::BurnChecked { amount, decimals } } 16 => { @@ -562,7 +588,12 @@ impl<'a> TokenInstruction<'a> { 21 => Self::GetAccountDataSize, 22 => Self::InitializeImmutableOwner, 23 => { - let (amount, _rest) = Self::unpack_u64(rest)?; + let (amount, _rest) = rest.split_at(8); + let amount = amount + .try_into() + .ok() + .map(u64::from_le_bytes) + .ok_or(InvalidInstruction)?; Self::AmountToUiAmount { amount } } 24 => { @@ -714,21 +745,6 @@ impl<'a> TokenInstruction<'a> { COption::None => buf.push(0), } } - - fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> { - let value = input - .get(..U64_BYTES) - .and_then(|slice| slice.try_into().ok()) - .map(u64::from_le_bytes) - .ok_or(TokenError::InvalidInstruction)?; - Ok((value, &input[U64_BYTES..])) - } - - fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> { - let (amount, rest) = Self::unpack_u64(input)?; - let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?; - Ok((amount, decimals, rest)) - } } /// Specifies the authority type for SetAuthority instructions @@ -1431,7 +1447,7 @@ pub fn is_valid_signer_index(index: usize) -> bool { #[cfg(test)] mod test { - use {super::*, proptest::prelude::*}; + use super::*; #[test] fn test_instruction_packing() { @@ -1673,14 +1689,4 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); } - - proptest! { - #![proptest_config(ProptestConfig::with_cases(1024))] - #[test] - fn test_instruction_unpack_panic( - data in prop::collection::vec(any::(), 0..255) - ) { - let _no_panic = TokenInstruction::unpack(&data); - } - } } diff --git a/program/src/processor.rs b/program/src/processor.rs index e617709..de7152a 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -13,10 +13,11 @@ use solana_program::{ msg, program::set_return_data, program_error::ProgramError, - program_memory::{sol_memcmp, sol_memset}, + program_memory::sol_memcmp, program_option::COption, program_pack::{IsInitialized, Pack}, pubkey::{Pubkey, PUBKEY_BYTES}, + system_program, sysvar::{rent::Rent, Sysvar}, }; @@ -696,8 +697,7 @@ impl Processor { .ok_or(TokenError::Overflow)?; **source_account_info.lamports.borrow_mut() = 0; - - sol_memset(*source_account_info.data.borrow_mut(), 0, Account::LEN); + delete_account(source_account_info)?; Ok(()) } @@ -1007,6 +1007,25 @@ impl Processor { } } +/// Helper function to mostly delete an account in a test environment. We could +/// potentially muck around the bytes assuming that a vec is passed in, but that +/// would be more trouble than it's worth. +#[cfg(not(target_arch = "bpf"))] +fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { + account_info.assign(&system_program::id()); + let mut account_data = account_info.data.borrow_mut(); + let data_len = account_data.len(); + solana_program::program_memory::sol_memset(*account_data, 0, data_len); + Ok(()) +} + +/// Helper function to totally delete an account on-chain +#[cfg(target_arch = "bpf")] +fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { + account_info.assign(&system_program::id()); + account_info.realloc(0, false) +} + #[cfg(test)] mod tests { use super::*; diff --git a/program/tests/close_account.rs b/program/tests/close_account.rs new file mode 100644 index 0000000..195a7aa --- /dev/null +++ b/program/tests/close_account.rs @@ -0,0 +1,202 @@ +#![cfg(feature = "test-bpf")] + +use { + solana_program_test::{processor, tokio, ProgramTest, ProgramTestContext}, + solana_sdk::{ + instruction::InstructionError, + program_pack::Pack, + pubkey::Pubkey, + signature::Signer, + signer::keypair::Keypair, + system_instruction, + transaction::{Transaction, TransactionError}, + }, + spl_token::{ + instruction, + processor::Processor, + state::{Account, Mint}, + }, +}; + +async fn setup_mint_and_account( + context: &mut ProgramTestContext, + mint: &Keypair, + token_account: &Keypair, + owner: &Pubkey, + token_program_id: &Pubkey, +) { + let rent = context.banks_client.get_rent().await.unwrap(); + let mint_authority_pubkey = Pubkey::new_unique(); + + let space = Mint::LEN; + let tx = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &context.payer.pubkey(), + &mint.pubkey(), + rent.minimum_balance(space), + space as u64, + &token_program_id, + ), + instruction::initialize_mint( + &token_program_id, + &mint.pubkey(), + &mint_authority_pubkey, + None, + 9, + ) + .unwrap(), + ], + Some(&context.payer.pubkey()), + &[&context.payer, mint], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + let space = Account::LEN; + let tx = Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &context.payer.pubkey(), + &token_account.pubkey(), + rent.minimum_balance(space), + space as u64, + &token_program_id, + ), + instruction::initialize_account( + &token_program_id, + &token_account.pubkey(), + &mint.pubkey(), + &owner, + ) + .unwrap(), + ], + Some(&context.payer.pubkey()), + &[&context.payer, &token_account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); +} + +#[tokio::test] +async fn success_init_after_close_account() { + let program_test = + ProgramTest::new("spl_token", spl_token::id(), processor!(Processor::process)); + let mut context = program_test.start_with_context().await; + let mint = Keypair::new(); + let token_account = Keypair::new(); + let owner = Keypair::new(); + let token_program_id = spl_token::id(); + setup_mint_and_account( + &mut context, + &mint, + &token_account, + &owner.pubkey(), + &token_program_id, + ) + .await; + + let destination = Pubkey::new_unique(); + let tx = Transaction::new_signed_with_payer( + &[ + instruction::close_account( + &token_program_id, + &token_account.pubkey(), + &destination, + &owner.pubkey(), + &[], + ) + .unwrap(), + system_instruction::create_account( + &context.payer.pubkey(), + &token_account.pubkey(), + 1_000_000_000, + Account::LEN as u64, + &token_program_id, + ), + instruction::initialize_account( + &token_program_id, + &token_account.pubkey(), + &mint.pubkey(), + &owner.pubkey(), + ) + .unwrap(), + ], + Some(&context.payer.pubkey()), + &[&context.payer, &owner, &token_account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + let destination = context + .banks_client + .get_account(destination) + .await + .unwrap() + .unwrap(); + assert!(destination.lamports > 0); +} + +#[tokio::test] +async fn fail_init_after_close_account() { + let program_test = + ProgramTest::new("spl_token", spl_token::id(), processor!(Processor::process)); + let mut context = program_test.start_with_context().await; + let mint = Keypair::new(); + let token_account = Keypair::new(); + let owner = Keypair::new(); + let token_program_id = spl_token::id(); + setup_mint_and_account( + &mut context, + &mint, + &token_account, + &owner.pubkey(), + &token_program_id, + ) + .await; + + let destination = Pubkey::new_unique(); + let tx = Transaction::new_signed_with_payer( + &[ + instruction::close_account( + &token_program_id, + &token_account.pubkey(), + &destination, + &owner.pubkey(), + &[], + ) + .unwrap(), + system_instruction::transfer( + &context.payer.pubkey(), + &token_account.pubkey(), + 1_000_000_000, + ), + instruction::initialize_account( + &token_program_id, + &token_account.pubkey(), + &mint.pubkey(), + &owner.pubkey(), + ) + .unwrap(), + ], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + #[allow(clippy::useless_conversion)] + let error: TransactionError = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err() + .unwrap() + .into(); + assert_eq!( + error, + TransactionError::InstructionError(2, InstructionError::InvalidAccountData) + ); + assert!(context + .banks_client + .get_account(destination) + .await + .unwrap() + .is_none()); +} From 49fb7abe2e76cca1f67c9a194b5533e02a6dcacf Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Thu, 4 Aug 2022 01:03:04 +0200 Subject: [PATCH 177/335] token/ata: Bump versions to 3.4.0 and 1.1.0, respectively (#3427) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 481319e..cf21ce7 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.3.1" +version = "3.4.0" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From f34ff629de7736e62e4b2953f4b7c1e15d5b9fe0 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 3 Aug 2022 23:25:07 -0700 Subject: [PATCH 178/335] Prep for spl-token v3.5.0 (#3426) * check that unpack is tolerant of small sizes (#3416) * Refactor unpack and make test more robust (#3417) * Refactor hasty fix to match token-2022 * Make test exhaustive * cargo fmt Co-authored-by: Michael Vines * Readd proptests without losing unit test, #3421 Co-authored-by: anatoly yakovenko Co-authored-by: Michael Vines --- program/src/instruction.rs | 83 ++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index c69c7bb..9dccdfb 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -15,6 +15,8 @@ use std::mem::size_of; pub const MIN_SIGNERS: usize = 1; /// Maximum number of multisignature signers (max N) pub const MAX_SIGNERS: usize = 11; +/// Serialized length of a u64, for unpacking +const U64_BYTES: usize = 8; /// Instructions supported by the token program. #[repr(C)] @@ -519,47 +521,19 @@ impl<'a> TokenInstruction<'a> { 10 => Self::FreezeAccount, 11 => Self::ThawAccount, 12 => { - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - + let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; Self::TransferChecked { amount, decimals } } 13 => { - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - + let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; Self::ApproveChecked { amount, decimals } } 14 => { - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - + let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; Self::MintToChecked { amount, decimals } } 15 => { - let (amount, rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; - let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?; - + let (amount, decimals, _rest) = Self::unpack_amount_decimals(rest)?; Self::BurnChecked { amount, decimals } } 16 => { @@ -588,12 +562,7 @@ impl<'a> TokenInstruction<'a> { 21 => Self::GetAccountDataSize, 22 => Self::InitializeImmutableOwner, 23 => { - let (amount, _rest) = rest.split_at(8); - let amount = amount - .try_into() - .ok() - .map(u64::from_le_bytes) - .ok_or(InvalidInstruction)?; + let (amount, _rest) = Self::unpack_u64(rest)?; Self::AmountToUiAmount { amount } } 24 => { @@ -745,6 +714,21 @@ impl<'a> TokenInstruction<'a> { COption::None => buf.push(0), } } + + fn unpack_u64(input: &[u8]) -> Result<(u64, &[u8]), ProgramError> { + let value = input + .get(..U64_BYTES) + .and_then(|slice| slice.try_into().ok()) + .map(u64::from_le_bytes) + .ok_or(TokenError::InvalidInstruction)?; + Ok((value, &input[U64_BYTES..])) + } + + fn unpack_amount_decimals(input: &[u8]) -> Result<(u64, u8, &[u8]), ProgramError> { + let (amount, rest) = Self::unpack_u64(input)?; + let (&decimals, rest) = rest.split_first().ok_or(TokenError::InvalidInstruction)?; + Ok((amount, decimals, rest)) + } } /// Specifies the authority type for SetAuthority instructions @@ -1447,7 +1431,7 @@ pub fn is_valid_signer_index(index: usize) -> bool { #[cfg(test)] mod test { - use super::*; + use {super::*, proptest::prelude::*}; #[test] fn test_instruction_packing() { @@ -1689,4 +1673,25 @@ mod test { let unpacked = TokenInstruction::unpack(&expect).unwrap(); assert_eq!(unpacked, check); } + + #[test] + fn test_instruction_unpack_panic() { + for i in 0..255u8 { + for j in 1..10 { + let mut data = vec![0; j]; + data[0] = i; + let _no_panic = TokenInstruction::unpack(&data); + } + } + } + + proptest! { + #![proptest_config(ProptestConfig::with_cases(1024))] + #[test] + fn test_instruction_unpack_proptest( + data in prop::collection::vec(any::(), 0..255) + ) { + let _no_panic = TokenInstruction::unpack(&data); + } + } } From 4d5ff3015ae5ad3316f2d2efdde6ab9f7a50716c Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 4 Aug 2022 00:09:38 -0700 Subject: [PATCH 179/335] Bump token to v3.5.0 and ata to v1.1.1 (#3430) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index cf21ce7..6cb8499 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.4.0" +version = "3.5.0" description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From bd9a8d4cc0203f8b3591461d5b05ce9bb1e5a212 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Tue, 16 Aug 2022 11:33:24 -0700 Subject: [PATCH 180/335] Bump solana to v1.10.35 (#3485) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 6cb8499..3978fec 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.10.33" +solana-program = "1.10.35" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.0" serial_test = "0.5.1" -solana-program-test = "1.10.33" -solana-sdk = "1.10.33" +solana-program-test = "1.10.35" +solana-sdk = "1.10.35" [lib] crate-type = ["cdylib", "lib"] From 8d6931905ebf18840e7c949ce4c4a1a23e0d2b5b Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Thu, 18 Aug 2022 13:38:10 +0200 Subject: [PATCH 181/335] token[-2022]: Change `target_arch` to `target_os` (#3493) --- program/src/processor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index de7152a..fbfe6bd 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1010,7 +1010,7 @@ impl Processor { /// Helper function to mostly delete an account in a test environment. We could /// potentially muck around the bytes assuming that a vec is passed in, but that /// would be more trouble than it's worth. -#[cfg(not(target_arch = "bpf"))] +#[cfg(not(target_os = "solana"))] fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { account_info.assign(&system_program::id()); let mut account_data = account_info.data.borrow_mut(); @@ -1020,7 +1020,7 @@ fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { } /// Helper function to totally delete an account on-chain -#[cfg(target_arch = "bpf")] +#[cfg(target_os = "solana")] fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { account_info.assign(&system_program::id()); account_info.realloc(0, false) From 344df71d0c0bab2aa0d30f6aaca424e06d4635f5 Mon Sep 17 00:00:00 2001 From: hana <81144685+2501babe@users.noreply.github.com> Date: Thu, 18 Aug 2022 12:16:02 -0700 Subject: [PATCH 182/335] Update rust to 1.60, solana to 1.11.6 (#3492) also change bpf to sbf throughout the codebase Co-authored-by: Jon Cinque --- program/Cargo.toml | 8 ++++---- program/tests/assert_instruction_count.rs | 2 +- program/tests/close_account.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 3978fec..80543d0 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -10,7 +10,7 @@ exclude = ["js/**"] [features] no-entrypoint = [] -test-bpf = [] +test-sbf = [] [dependencies] arrayref = "0.3.6" @@ -18,15 +18,15 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.10.35" +solana-program = "1.11.6" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.0" serial_test = "0.5.1" -solana-program-test = "1.10.35" -solana-sdk = "1.10.35" +solana-program-test = "1.11.6" +solana-sdk = "1.11.6" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs index d663c54..a6df337 100644 --- a/program/tests/assert_instruction_count.rs +++ b/program/tests/assert_instruction_count.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] mod action; use { diff --git a/program/tests/close_account.rs b/program/tests/close_account.rs index 195a7aa..25adda2 100644 --- a/program/tests/close_account.rs +++ b/program/tests/close_account.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "test-bpf")] +#![cfg(feature = "test-sbf")] use { solana_program_test::{processor, tokio, ProgramTest, ProgramTestContext}, From f9e12f40f6a30da50974b02c79deb3acabe092fd Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Thu, 15 Sep 2022 13:16:53 +0200 Subject: [PATCH 183/335] clippy: Deny integer arithmetic, add allows where needed (#3606) --- program/src/lib.rs | 1 + program/tests/close_account.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/program/src/lib.rs b/program/src/lib.rs index 2252ac1..2019474 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::integer_arithmetic)] #![deny(missing_docs)] #![cfg_attr(not(test), forbid(unsafe_code))] diff --git a/program/tests/close_account.rs b/program/tests/close_account.rs index 25adda2..8c9cc4f 100644 --- a/program/tests/close_account.rs +++ b/program/tests/close_account.rs @@ -36,10 +36,10 @@ async fn setup_mint_and_account( &mint.pubkey(), rent.minimum_balance(space), space as u64, - &token_program_id, + token_program_id, ), instruction::initialize_mint( - &token_program_id, + token_program_id, &mint.pubkey(), &mint_authority_pubkey, None, @@ -60,18 +60,18 @@ async fn setup_mint_and_account( &token_account.pubkey(), rent.minimum_balance(space), space as u64, - &token_program_id, + token_program_id, ), instruction::initialize_account( - &token_program_id, + token_program_id, &token_account.pubkey(), &mint.pubkey(), - &owner, + owner, ) .unwrap(), ], Some(&context.payer.pubkey()), - &[&context.payer, &token_account], + &[&context.payer, token_account], context.last_blockhash, ); context.banks_client.process_transaction(tx).await.unwrap(); From 4e0389b245fd452f44d25246bedeac0fa77952b6 Mon Sep 17 00:00:00 2001 From: timkoopmans Date: Mon, 3 Oct 2022 19:57:36 +1000 Subject: [PATCH 184/335] typo --- program/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/error.rs b/program/src/error.rs index 454aa9e..72461a0 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -42,7 +42,7 @@ pub enum TokenError { #[error("Invalid number of required signers")] InvalidNumberOfRequiredSigners, /// State is uninitialized. - #[error("State is unititialized")] + #[error("State is uninitialized")] UninitializedState, // 10 From 380c8d838491e617cd10486b1f001eb35ee1173a Mon Sep 17 00:00:00 2001 From: hanako mumei <81144685+2501babe@users.noreply.github.com> Date: Tue, 11 Oct 2022 12:04:28 -0700 Subject: [PATCH 185/335] update solana to 1.14.4 --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 80543d0..c2f8527 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.11.6" +solana-program = "1.14.4" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.0" serial_test = "0.5.1" -solana-program-test = "1.11.6" -solana-sdk = "1.11.6" +solana-program-test = "1.14.4" +solana-sdk = "1.14.4" [lib] crate-type = ["cdylib", "lib"] From 3224ecb1f3c22ed05995549333559d29aab60daf Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 27 Oct 2022 07:59:25 +0900 Subject: [PATCH 186/335] upgrade solana-program to 1.14.6 (#3765) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index c2f8527..dc6d459 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.14.4" +solana-program = "1.14.6" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.0" serial_test = "0.5.1" -solana-program-test = "1.14.4" -solana-sdk = "1.14.4" +solana-program-test = "1.14.6" +solana-sdk = "1.14.6" [lib] crate-type = ["cdylib", "lib"] From bf6444776daccb1abaeb33c34a9667f7be7b0d99 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Fri, 28 Oct 2022 18:03:20 -0400 Subject: [PATCH 187/335] token: Fix some spelling mistakes (#3777) --- program/src/instruction.rs | 2 +- program/src/lib.rs | 4 ++-- program/src/processor.rs | 2 +- program/src/state.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 9dccdfb..897be5b 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -466,7 +466,7 @@ pub enum TokenInstruction<'a> { }, // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the // latter remains a superset of this instruction set. New variants also need to be added to - // token/js/src/instructions/types.ts to maintain @solana/spl-token compatability + // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility } impl<'a> TokenInstruction<'a> { /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). diff --git a/program/src/lib.rs b/program/src/lib.rs index 2019474..e449506 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -53,12 +53,12 @@ pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { s } -/// Try to convert a UI represenation of a token amount to its raw amount using the given decimals +/// Try to convert a UI representation of a token amount to its raw amount using the given decimals /// field pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { let decimals = decimals as usize; let mut parts = ui_amount.split('.'); - let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at least len == 1 + let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at least length == 1 let after_decimal = parts.next().unwrap_or(""); let after_decimal = after_decimal.trim_end_matches('0'); if (amount_str.is_empty() && after_decimal.is_empty()) diff --git a/program/src/processor.rs b/program/src/processor.rs index fbfe6bd..6da8d80 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -6066,7 +6066,7 @@ mod tests { let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX); - // atttempt to mint one more to the other account + // attempt to mint one more to the other account assert_eq!( Err(TokenError::Overflow.into()), do_process_instruction( diff --git a/program/src/state.rs b/program/src/state.rs index 6070141..ba4b193 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -435,7 +435,7 @@ mod tests { let result = Account::unpack_account_owner(&src); assert_eq!(result, Option::None); - // The right account data size and intialized, unpack will return some key + // The right account data size and initialized, unpack will return some key let mut src: [u8; Account::LEN] = [0; Account::LEN]; src[ACCOUNT_INITIALIZED_INDEX] = AccountState::Initialized as u8; let result = Account::unpack_account_owner(&src); From 3fd13116625df9676df5af9ae43eac93d7d129bf Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Tue, 6 Dec 2022 12:59:00 +0900 Subject: [PATCH 188/335] update solana to 1.14.10 (#3872) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index dc6d459..be8dc96 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.14.6" +solana-program = "1.14.10" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.0" serial_test = "0.5.1" -solana-program-test = "1.14.6" -solana-sdk = "1.14.6" +solana-program-test = "1.14.10" +solana-sdk = "1.14.10" [lib] crate-type = ["cdylib", "lib"] From f830e4d6cc6907c7784820fbef7a981337fdc8bf Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 13 Dec 2022 15:56:12 +0100 Subject: [PATCH 189/335] clippy: Remove `useless_conversion` (#3899) --- program/tests/close_account.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/program/tests/close_account.rs b/program/tests/close_account.rs index 8c9cc4f..8425fe2 100644 --- a/program/tests/close_account.rs +++ b/program/tests/close_account.rs @@ -181,14 +181,12 @@ async fn fail_init_after_close_account() { &[&context.payer, &owner], context.last_blockhash, ); - #[allow(clippy::useless_conversion)] - let error: TransactionError = context + let error = context .banks_client .process_transaction(tx) .await .unwrap_err() - .unwrap() - .into(); + .unwrap(); assert_eq!( error, TransactionError::InstructionError(2, InstructionError::InvalidAccountData) From 9ac2b06d0cdfae44bcee8380417b65ab3580cf5a Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 13 Dec 2022 23:46:26 +0100 Subject: [PATCH 190/335] Update repo to `edition = "2021"` (#3900) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index be8dc96..0c0d5fa 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -5,7 +5,7 @@ description = "Solana Program Library Token" authors = ["Solana Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" -edition = "2018" +edition = "2021" exclude = ["js/**"] [features] From b299d0ca74056ca69360a7c18a784231a538c797 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Thu, 19 Jan 2023 21:47:03 +0100 Subject: [PATCH 191/335] ci: Update repo to Solana 1.14.12 (#3989) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 0c0d5fa..8edd4dd 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.4" -solana-program = "1.14.10" +solana-program = "1.14.12" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.0" serial_test = "0.5.1" -solana-program-test = "1.14.10" -solana-sdk = "1.14.10" +solana-program-test = "1.14.12" +solana-sdk = "1.14.12" [lib] crate-type = ["cdylib", "lib"] From 005ac5234b57bca0cb5738e1176fd7d872d24ce5 Mon Sep 17 00:00:00 2001 From: joeaba <77398477+joeaba@users.noreply.github.com> Date: Tue, 31 Jan 2023 08:06:36 -0500 Subject: [PATCH 192/335] chore: update maintainer references (#4008) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 8edd4dd..f7303e6 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -2,7 +2,7 @@ name = "spl-token" version = "3.5.0" description = "Solana Program Library Token" -authors = ["Solana Maintainers "] +authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" license = "Apache-2.0" edition = "2021" From 5d1c5df9cde1582a7050617b8032c64475300a72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Feb 2023 16:12:15 +0100 Subject: [PATCH 193/335] build(deps): bump num_enum from 0.5.7 to 0.5.9 (#4020) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index f7303e6..e3bbd0a 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,7 +17,7 @@ arrayref = "0.3.6" bytemuck = "1.7.2" num-derive = "0.3" num-traits = "0.2" -num_enum = "0.5.4" +num_enum = "0.5.9" solana-program = "1.14.12" thiserror = "1.0" From 744e44917e5d4aefb7aeff5a88f658c94c4047b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 20:27:18 +0100 Subject: [PATCH 194/335] build(deps): bump bytemuck from 1.12.1 to 1.13.0 (#4027) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index e3bbd0a..93bdc4f 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.6" -bytemuck = "1.7.2" +bytemuck = "1.13.0" num-derive = "0.3" num-traits = "0.2" num_enum = "0.5.9" From 8bf30cf273517cd1fdc78c97b25e6c9d2b306e4a Mon Sep 17 00:00:00 2001 From: Pierre Date: Tue, 4 Apr 2023 08:30:52 +1000 Subject: [PATCH 195/335] More direct delegate test (#4092) --- program/src/processor.rs | 75 ++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/program/src/processor.rs b/program/src/processor.rs index 6da8d80..452b16f 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -2115,6 +2115,48 @@ mod tests { ) .unwrap(); + // not a delegate of source account + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner2_key, // <-- incorrect owner or delegate + &[], + 1, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 101 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + // transfer via delegate do_process_instruction( transfer( @@ -2144,7 +2186,7 @@ mod tests { &account2_key, &delegate_key, &[], - 100 + 1 ) .unwrap(), vec![ @@ -4503,18 +4545,31 @@ mod tests { // not a delegate of source account assert_eq!( - Err(TokenError::InsufficientFunds.into()), + Err(TokenError::OwnerMismatch.into()), do_process_instruction( burn( &program_id, &account_key, &mint_key, - &owner_key, + &owner2_key, // <-- incorrect owner or delegate &[], - 100_000_000 + 1, ) .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 85).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], ) ); @@ -4539,15 +4594,7 @@ mod tests { assert_eq!( Err(TokenError::OwnerMismatch.into()), do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), + burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 1).unwrap(), vec![ &mut account_account, &mut mint_account, From 55fce97cbe8b70b251c6ce2615550b9710b0b2d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 May 2023 13:31:57 +0200 Subject: [PATCH 196/335] build(deps): bump num_enum from 0.5.9 to 0.6.1 (#4156) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 93bdc4f..6720365 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,7 +17,7 @@ arrayref = "0.3.6" bytemuck = "1.13.0" num-derive = "0.3" num-traits = "0.2" -num_enum = "0.5.9" +num_enum = "0.6.1" solana-program = "1.14.12" thiserror = "1.0" From 409e98d41904adabd59747a076c25dc5b372f90f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 22:53:57 +0200 Subject: [PATCH 197/335] build(deps): bump proptest from 1.0.0 to 1.1.0 (#4184) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 6720365..2c3aa2a 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -23,7 +23,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" -proptest = "1.0" +proptest = "1.1" serial_test = "0.5.1" solana-program-test = "1.14.12" solana-sdk = "1.14.12" From 15db8d4fbd0d2916d9da3cde842f4aa80b6bed2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 20:51:46 +0200 Subject: [PATCH 198/335] build(deps): bump serial_test from 0.5.1 to 0.8.0 (#4206) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 2c3aa2a..adc1311 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -24,7 +24,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.1" -serial_test = "0.5.1" +serial_test = "0.8.0" solana-program-test = "1.14.12" solana-sdk = "1.14.12" From ce7cd5fe57a658298aa11746e54e72b51068e74d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 13:53:18 +0200 Subject: [PATCH 199/335] build(deps): bump arrayref from 0.3.6 to 0.3.7 (#4233) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index adc1311..37c81f7 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -13,7 +13,7 @@ no-entrypoint = [] test-sbf = [] [dependencies] -arrayref = "0.3.6" +arrayref = "0.3.7" bytemuck = "1.13.0" num-derive = "0.3" num-traits = "0.2" From bf45d56c1040c8af9a6722650dd370905fc73b4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 May 2023 13:23:23 +0200 Subject: [PATCH 200/335] build(deps): bump serial_test from 0.8.0 to 2.0.0 (#4253) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 37c81f7..cd6d97d 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -24,7 +24,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.1" -serial_test = "0.8.0" +serial_test = "2.0.0" solana-program-test = "1.14.12" solana-sdk = "1.14.12" From e473f8c284b50b5f860fa6d46279800f23aa108f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 12:42:34 +0200 Subject: [PATCH 201/335] build(deps): bump bytemuck from 1.13.0 to 1.13.1 (#4272) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index cd6d97d..6242804 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" -bytemuck = "1.13.0" +bytemuck = "1.13.1" num-derive = "0.3" num-traits = "0.2" num_enum = "0.6.1" From 056c492fd6011c0d19669103128dbab20028cf5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 23:10:53 +0200 Subject: [PATCH 202/335] build(deps): bump proptest from 1.1.0 to 1.2.0 (#4378) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 6242804..7afb888 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -23,7 +23,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" -proptest = "1.1" +proptest = "1.2" serial_test = "2.0.0" solana-program-test = "1.14.12" solana-sdk = "1.14.12" From fbb4ea0db506b512b9a21025c3a968ce482336fb Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Thu, 1 Jun 2023 03:00:40 +0200 Subject: [PATCH 203/335] docs: Be really clear that token-2022 is still under audit (#4435) --- program/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 program/README.md diff --git a/program/README.md b/program/README.md new file mode 100644 index 0000000..02cbb7c --- /dev/null +++ b/program/README.md @@ -0,0 +1,13 @@ +# Token program + +A token program on the Solana blockchain, usable for fungible and non-fungible tokens. + +This program provides an interface and implementation that third parties can +utilize to create and use their tokens. + +Full documentation is available at https://spl.solana.com/token + +## Audit + +The repository [README](https://github.com/solana-labs/solana-program-library#audits) +contains information about program audits. From 1fbee019568a1abcf694d1f889471cb2a90b1127 Mon Sep 17 00:00:00 2001 From: Sergey Kaunov Date: Mon, 5 Jun 2023 14:19:10 +0300 Subject: [PATCH 204/335] Add link to doc: instruction.rs (#4464) --- program/src/instruction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 897be5b..4e7fbba 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -397,7 +397,7 @@ pub enum TokenInstruction<'a> { /// account. m: u8, }, - /// Like InitializeMint, but does not require the Rent sysvar to be provided + /// Like [`InitializeMint`], but does not require the Rent sysvar to be provided /// /// Accounts expected by this instruction: /// From 09450daf1874f55e33429a51178e91550a5703e7 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Mon, 26 Jun 2023 14:42:02 +0200 Subject: [PATCH 205/335] Update Solana to 1.16.1 and Rust to 1.69 (#4592) #### Problem The 1.16 Solana crates are out, but SPL is still on 1.14 and needs the new functionality. #### Solution Update the: * rust version to 1.69 * nightly to 2023-04-19 * solana tools to 1.16.1 * solana crates to 1.16.1 * borsh to 0.10 And fix: * new clippy warnings * deprecated warnings in the new solana crates --- program/Cargo.toml | 6 +++--- program/src/instruction.rs | 26 +++++++++++++------------- program/src/processor.rs | 14 +++++++------- program/src/state.rs | 11 +++-------- 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 7afb888..87bdde7 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.13.1" num-derive = "0.3" num-traits = "0.2" num_enum = "0.6.1" -solana-program = "1.14.12" +solana-program = "1.16.1" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.2" serial_test = "2.0.0" -solana-program-test = "1.14.12" -solana-sdk = "1.14.12" +solana-program-test = "1.16.1" +solana-sdk = "1.16.1" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 4e7fbba..e798abd 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -487,7 +487,7 @@ impl<'a> TokenInstruction<'a> { } 1 => Self::InitializeAccount, 2 => { - let &m = rest.get(0).ok_or(InvalidInstruction)?; + let &m = rest.first().ok_or(InvalidInstruction)?; Self::InitializeMultisig { m } } 3 | 4 | 7 | 8 => { @@ -546,7 +546,7 @@ impl<'a> TokenInstruction<'a> { Self::InitializeAccount3 { owner } } 19 => { - let &m = rest.get(0).ok_or(InvalidInstruction)?; + let &m = rest.first().ok_or(InvalidInstruction)?; Self::InitializeMultisig2 { m } } 20 => { @@ -686,7 +686,7 @@ impl<'a> TokenInstruction<'a> { fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> { if input.len() >= 32 { let (key, rest) = input.split_at(32); - let pk = Pubkey::new(key); + let pk = Pubkey::try_from(key).map_err(|_| TokenError::InvalidInstruction)?; Ok((pk, rest)) } else { Err(TokenError::InvalidInstruction.into()) @@ -698,7 +698,7 @@ impl<'a> TokenInstruction<'a> { Option::Some((&0, rest)) => Ok((COption::None, rest)), Option::Some((&1, rest)) if rest.len() >= 32 => { let (key, rest) = rest.split_at(32); - let pk = Pubkey::new(key); + let pk = Pubkey::try_from(key).map_err(|_| TokenError::InvalidInstruction)?; Ok((COption::Some(pk), rest)) } _ => Err(TokenError::InvalidInstruction.into()), @@ -1437,7 +1437,7 @@ mod test { fn test_instruction_packing() { let check = TokenInstruction::InitializeMint { decimals: 2, - mint_authority: Pubkey::new(&[1u8; 32]), + mint_authority: Pubkey::new_from_array([1u8; 32]), freeze_authority: COption::None, }; let packed = check.pack(); @@ -1450,8 +1450,8 @@ mod test { let check = TokenInstruction::InitializeMint { decimals: 2, - mint_authority: Pubkey::new(&[2u8; 32]), - freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), + mint_authority: Pubkey::new_from_array([2u8; 32]), + freeze_authority: COption::Some(Pubkey::new_from_array([3u8; 32])), }; let packed = check.pack(); let mut expect = vec![0u8, 2]; @@ -1499,7 +1499,7 @@ mod test { let check = TokenInstruction::SetAuthority { authority_type: AuthorityType::FreezeAccount, - new_authority: COption::Some(Pubkey::new(&[4u8; 32])), + new_authority: COption::Some(Pubkey::new_from_array([4u8; 32])), }; let packed = check.pack(); let mut expect = Vec::from([6u8, 1]); @@ -1585,7 +1585,7 @@ mod test { assert_eq!(unpacked, check); let check = TokenInstruction::InitializeAccount2 { - owner: Pubkey::new(&[2u8; 32]), + owner: Pubkey::new_from_array([2u8; 32]), }; let packed = check.pack(); let mut expect = vec![16u8]; @@ -1602,7 +1602,7 @@ mod test { assert_eq!(unpacked, check); let check = TokenInstruction::InitializeAccount3 { - owner: Pubkey::new(&[2u8; 32]), + owner: Pubkey::new_from_array([2u8; 32]), }; let packed = check.pack(); let mut expect = vec![18u8]; @@ -1620,7 +1620,7 @@ mod test { let check = TokenInstruction::InitializeMint2 { decimals: 2, - mint_authority: Pubkey::new(&[1u8; 32]), + mint_authority: Pubkey::new_from_array([1u8; 32]), freeze_authority: COption::None, }; let packed = check.pack(); @@ -1633,8 +1633,8 @@ mod test { let check = TokenInstruction::InitializeMint2 { decimals: 2, - mint_authority: Pubkey::new(&[2u8; 32]), - freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])), + mint_authority: Pubkey::new_from_array([2u8; 32]), + freeze_authority: COption::Some(Pubkey::new_from_array([3u8; 32])), }; let packed = check.pack(); let mut expect = vec![20u8, 2]; diff --git a/program/src/processor.rs b/program/src/processor.rs index 452b16f..7056f2e 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1166,11 +1166,11 @@ mod tests { fn test_pack_unpack() { // Mint let check = Mint { - mint_authority: COption::Some(Pubkey::new(&[1; 32])), + mint_authority: COption::Some(Pubkey::new_from_array([1; 32])), supply: 42, decimals: 7, is_initialized: true, - freeze_authority: COption::Some(Pubkey::new(&[2; 32])), + freeze_authority: COption::Some(Pubkey::new_from_array([2; 32])), }; let mut packed = vec![0; Mint::get_packed_len() + 1]; assert_eq!( @@ -1195,14 +1195,14 @@ mod tests { // Account let check = Account { - mint: Pubkey::new(&[1; 32]), - owner: Pubkey::new(&[2; 32]), + mint: Pubkey::new_from_array([1; 32]), + owner: Pubkey::new_from_array([2; 32]), amount: 3, - delegate: COption::Some(Pubkey::new(&[4; 32])), + delegate: COption::Some(Pubkey::new_from_array([4; 32])), state: AccountState::Frozen, is_native: COption::Some(5), delegated_amount: 6, - close_authority: COption::Some(Pubkey::new(&[7; 32])), + close_authority: COption::Some(Pubkey::new_from_array([7; 32])), }; let mut packed = vec![0; Account::get_packed_len() + 1]; assert_eq!( @@ -1233,7 +1233,7 @@ mod tests { m: 1, n: 2, is_initialized: true, - signers: [Pubkey::new(&[3; 32]); MAX_SIGNERS], + signers: [Pubkey::new_from_array([3; 32]); MAX_SIGNERS], }; let mut packed = vec![0; Multisig::get_packed_len() + 1]; assert_eq!( diff --git a/program/src/state.rs b/program/src/state.rs index ba4b193..8723065 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -178,9 +178,10 @@ impl Pack for Account { /// Account state. #[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive)] +#[derive(Clone, Copy, Debug, Default, PartialEq, TryFromPrimitive)] pub enum AccountState { /// Account is not yet initialized + #[default] Uninitialized, /// Account is initialized; the account owner and/or delegate may perform permitted operations /// on this account @@ -190,12 +191,6 @@ pub enum AccountState { Frozen, } -impl Default for AccountState { - fn default() -> Self { - AccountState::Uninitialized - } -} - /// Multisignature data. #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq)] @@ -232,7 +227,7 @@ impl Pack for Multisig { signers: [Pubkey::new_from_array([0u8; 32]); MAX_SIGNERS], }; for (src, dst) in signers_flat.chunks(32).zip(result.signers.iter_mut()) { - *dst = Pubkey::new(src); + *dst = Pubkey::try_from(src).map_err(|_| ProgramError::InvalidAccountData)?; } Ok(result) } From c5932839f1f46296e41dcfff41c550fa15c61aaa Mon Sep 17 00:00:00 2001 From: Joe C Date: Tue, 27 Jun 2023 08:34:11 -0400 Subject: [PATCH 206/335] bump token & co. (#4612) * bump token & token cli * token version fix --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 87bdde7..4233259 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "3.5.0" +version = "4.0.0" description = "Solana Program Library Token" authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From 95894f871ff9aeed5a8e495f51129606b472bb61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Jun 2023 14:03:21 +0200 Subject: [PATCH 207/335] build(deps): bump num-derive from 0.3.3 to 0.4.0 (#4659) * build(deps): bump num-derive from 0.3.3 to 0.4.0 Bumps [num-derive](https://github.com/rust-num/num-derive) from 0.3.3 to 0.4.0. - [Changelog](https://github.com/rust-num/num-derive/blob/master/RELEASES.md) - [Commits](https://github.com/rust-num/num-derive/compare/num-derive-0.3.3...num-derive-0.4.0) --- updated-dependencies: - dependency-name: num-derive dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Unbump hashbrown in borsh --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jon Cinque --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 4233259..ea22d01 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -15,7 +15,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" bytemuck = "1.13.1" -num-derive = "0.3" +num-derive = "0.4" num-traits = "0.2" num_enum = "0.6.1" solana-program = "1.16.1" From 05038a43cc90bc46ff1d392f4144160d98c164e8 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 13 Jul 2023 11:06:07 +0900 Subject: [PATCH 208/335] Upgrade to solana 1.16.3 (#4679) * upgrade to solana 1.16.3 * bring down hashbrown dependency to 0.12.3 --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index ea22d01..593124a 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.13.1" num-derive = "0.4" num-traits = "0.2" num_enum = "0.6.1" -solana-program = "1.16.1" +solana-program = "1.16.3" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.2" serial_test = "2.0.0" -solana-program-test = "1.16.1" -solana-sdk = "1.16.1" +solana-program-test = "1.16.3" +solana-sdk = "1.16.3" [lib] crate-type = ["cdylib", "lib"] From e8819d740dd9edb1a2f461e6154310f2668f745b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 12:04:17 +0200 Subject: [PATCH 209/335] build(deps): bump num_enum from 0.6.1 to 0.7.0 (#5003) Bumps [num_enum](https://github.com/illicitonion/num_enum) from 0.6.1 to 0.7.0. - [Commits](https://github.com/illicitonion/num_enum/commits) --- updated-dependencies: - dependency-name: num_enum dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 593124a..ee099eb 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,7 +17,7 @@ arrayref = "0.3.7" bytemuck = "1.13.1" num-derive = "0.4" num-traits = "0.2" -num_enum = "0.6.1" +num_enum = "0.7.0" solana-program = "1.16.3" thiserror = "1.0" From cbb15fb0ce71c60a4785a9f069d6e9f682e96ca8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:05:46 -0400 Subject: [PATCH 210/335] build(deps): bump bytemuck from 1.13.1 to 1.14.0 (#5210) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.13.1 to 1.14.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.13.1...v1.14.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index ee099eb..bdf8061 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" -bytemuck = "1.13.1" +bytemuck = "1.14.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.0" From a6b6e91e105995d82becfbcf5ac9236f161defe3 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Thu, 21 Sep 2023 10:44:57 +0200 Subject: [PATCH 211/335] Bump repo to 1.16.13 (#5324) * Run update script * Update everything to use non-deprecated functions --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index bdf8061..00542bf 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.14.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.0" -solana-program = "1.16.3" +solana-program = "1.16.13" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.2" serial_test = "2.0.0" -solana-program-test = "1.16.3" -solana-sdk = "1.16.3" +solana-program-test = "1.16.13" +solana-sdk = "1.16.13" [lib] crate-type = ["cdylib", "lib"] From 951cd0ae564c611bdcedae1db60fcac3124e5275 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:49:41 -0400 Subject: [PATCH 212/335] build(deps): bump proptest from 1.2.0 to 1.3.1 (#5398) Bumps [proptest](https://github.com/proptest-rs/proptest) from 1.2.0 to 1.3.1. - [Release notes](https://github.com/proptest-rs/proptest/releases) - [Changelog](https://github.com/proptest-rs/proptest/blob/master/CHANGELOG.md) - [Commits](https://github.com/proptest-rs/proptest/compare/v1.2.0...v1.3.1) --- updated-dependencies: - dependency-name: proptest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 00542bf..0352df8 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -23,7 +23,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" -proptest = "1.2" +proptest = "1.3" serial_test = "2.0.0" solana-program-test = "1.16.13" solana-sdk = "1.16.13" From 8a85aecf4fc455890e5b92db158ec9f4a754a32c Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Tue, 10 Oct 2023 21:02:47 -0400 Subject: [PATCH 213/335] chore: Bump Solana crates to 1.16.16 (#5494) --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 0352df8..3fdf234 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.14.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.0" -solana-program = "1.16.13" +solana-program = "1.16.16" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.3" serial_test = "2.0.0" -solana-program-test = "1.16.13" -solana-sdk = "1.16.13" +solana-program-test = "1.16.16" +solana-sdk = "1.16.16" [lib] crate-type = ["cdylib", "lib"] From cde93206cc7d4ea10a7402359b16091ea103c55d Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Thu, 19 Oct 2023 18:04:18 +0200 Subject: [PATCH 214/335] ci: Bump repo to Solana 1.17 (#5575) * Update workspace for new cargo resolver, remove ntapi patch * Update Rust versions * Update dependencies with `./update-solana-dependencies.sh 1.17.2` * Update lockfile * Fix build errors * Run clippy with `--fix` * concurrent-merkle-tree: Fix function to not use mutable ref * Replace StakeState with StakeStateV2 * governance: Fix clippy lint * governance: Fix unnecessary mut * Allow `clippy::items_after_module` * token: Make error tests clearer * token-2022: Fix private glob re-export * token-upgrade-cli: Replace validator with parser * single-pool-cli: Fix parsers * ci: Update clippy command * Update anchor version * token-metadata: Use `no-entrypoint` feature in token-2022 * ci: Add protobuf-compiler to build deps * discriminator-syn: *Don't* specify type of lib to build * ci: Blast directories in cargo-build-test * account-compression: Update build and lockfile * Update token-group and feature-gate * single-pool: revert WrongStakeStateV2 * stake-pool: revert WrongStakeStateV2 * stake-pool-py: revert StakeStateV2 --------- Co-authored-by: hanako mumei <81144685+2501babe@users.noreply.github.com> --- program/Cargo.toml | 6 +++--- program/src/lib.rs | 2 +- program/src/processor.rs | 8 +++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 3fdf234..51fac3e 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.14.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.0" -solana-program = "1.16.16" +solana-program = "1.17.2" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.3" serial_test = "2.0.0" -solana-program-test = "1.16.16" -solana-sdk = "1.16.16" +solana-program-test = "1.17.2" +solana-sdk = "1.17.2" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/src/lib.rs b/program/src/lib.rs index e449506..1eb3855 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -1,4 +1,4 @@ -#![allow(clippy::integer_arithmetic)] +#![allow(clippy::arithmetic_side_effects)] #![deny(missing_docs)] #![cfg_attr(not(test), forbid(unsafe_code))] diff --git a/program/src/processor.rs b/program/src/processor.rs index 7056f2e..6c9b0f4 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1147,9 +1147,11 @@ mod tests { } #[test] - #[should_panic(expected = "Custom(3)")] - fn test_error_unwrap() { - Err::<(), ProgramError>(return_token_error_as_program_error()).unwrap(); + fn test_error_as_custom() { + assert_eq!( + return_token_error_as_program_error(), + ProgramError::Custom(3) + ); } #[test] From 97e29e2cc24259289117a83f729c892080f92c39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Oct 2023 22:03:45 +0200 Subject: [PATCH 215/335] build(deps): bump num_enum from 0.7.0 to 0.7.1 (#5687) Bumps [num_enum](https://github.com/illicitonion/num_enum) from 0.7.0 to 0.7.1. - [Commits](https://github.com/illicitonion/num_enum/commits) --- updated-dependencies: - dependency-name: num_enum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 51fac3e..17c1b4d 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,7 +17,7 @@ arrayref = "0.3.7" bytemuck = "1.14.0" num-derive = "0.4" num-traits = "0.2" -num_enum = "0.7.0" +num_enum = "0.7.1" solana-program = "1.17.2" thiserror = "1.0" From 1679cf938869c68f48b3138825f1c715fd37e124 Mon Sep 17 00:00:00 2001 From: Joe C Date: Wed, 8 Nov 2023 20:36:07 +0000 Subject: [PATCH 216/335] rustfmt: use entrypoint full path This PR swaps any calls to the `entrypoint!` macro with the full path, ie: `solana_program::entrypoint!`. This will play a role in the effort to introduce a linting standard to SPL. --- program/src/entrypoint.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs index 5331575..6d9ad5d 100644 --- a/program/src/entrypoint.rs +++ b/program/src/entrypoint.rs @@ -2,11 +2,11 @@ use crate::{error::TokenError, processor::Processor}; use solana_program::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, - program_error::PrintProgramError, pubkey::Pubkey, + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, }; -entrypoint!(process_instruction); +solana_program::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], From c3f12a1f626224ec7f98297cedf241265427541a Mon Sep 17 00:00:00 2001 From: Joe C Date: Wed, 8 Nov 2023 20:38:31 +0000 Subject: [PATCH 217/335] rustfmt: format imports This PR adds import formatting configurations to the repository's `rustfmt.toml` file, and the associated changes from `cargo +nightly fmt --all`. --- program/src/entrypoint.rs | 10 +++--- program/src/error.rs | 14 ++++---- program/src/instruction.rs | 19 ++++++----- program/src/native_mint.rs | 3 +- program/src/processor.rs | 68 ++++++++++++++++++++------------------ program/src/state.rs | 18 +++++----- 6 files changed, 71 insertions(+), 61 deletions(-) diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs index 6d9ad5d..366ee78 100644 --- a/program/src/entrypoint.rs +++ b/program/src/entrypoint.rs @@ -1,9 +1,11 @@ //! Program entrypoint -use crate::{error::TokenError, processor::Processor}; -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, - pubkey::Pubkey, +use { + crate::{error::TokenError, processor::Processor}, + solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, + pubkey::Pubkey, + }, }; solana_program::entrypoint!(process_instruction); diff --git a/program/src/error.rs b/program/src/error.rs index 72461a0..a758d2c 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -1,12 +1,14 @@ //! Error types -use num_derive::FromPrimitive; -use solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, +use { + num_derive::FromPrimitive, + solana_program::{ + decode_error::DecodeError, + msg, + program_error::{PrintProgramError, ProgramError}, + }, + thiserror::Error, }; -use thiserror::Error; /// Errors that may be returned by the Token program. #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] diff --git a/program/src/instruction.rs b/program/src/instruction.rs index e798abd..067fde5 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -1,15 +1,16 @@ //! Instruction types -use crate::{check_program_account, error::TokenError}; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_option::COption, - pubkey::Pubkey, - sysvar, +use { + crate::{check_program_account, error::TokenError}, + solana_program::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + program_option::COption, + pubkey::Pubkey, + sysvar, + }, + std::{convert::TryInto, mem::size_of}, }; -use std::convert::TryInto; -use std::mem::size_of; /// Minimum number of multisignature signers (min N) pub const MIN_SIGNERS: usize = 1; diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs index 0502f9f..37f7555 100644 --- a/program/src/native_mint.rs +++ b/program/src/native_mint.rs @@ -8,8 +8,7 @@ solana_program::declare_id!("So11111111111111111111111111111111111111112"); #[cfg(test)] mod tests { - use super::*; - use solana_program::native_token::*; + use {super::*, solana_program::native_token::*}; #[test] fn test_decimals() { diff --git a/program/src/processor.rs b/program/src/processor.rs index 6c9b0f4..a849382 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1,24 +1,26 @@ //! Program state processor -use crate::{ - amount_to_ui_amount_string_trimmed, - error::TokenError, - instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, - state::{Account, AccountState, Mint, Multisig}, - try_ui_amount_into_amount, -}; -use solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program::set_return_data, - program_error::ProgramError, - program_memory::sol_memcmp, - program_option::COption, - program_pack::{IsInitialized, Pack}, - pubkey::{Pubkey, PUBKEY_BYTES}, - system_program, - sysvar::{rent::Rent, Sysvar}, +use { + crate::{ + amount_to_ui_amount_string_trimmed, + error::TokenError, + instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS}, + state::{Account, AccountState, Mint, Multisig}, + try_ui_amount_into_amount, + }, + solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + msg, + program::set_return_data, + program_error::ProgramError, + program_memory::sol_memcmp, + program_option::COption, + program_pack::{IsInitialized, Pack}, + pubkey::{Pubkey, PUBKEY_BYTES}, + system_program, + sysvar::{rent::Rent, Sysvar}, + }, }; /// Program state handler. @@ -1028,20 +1030,22 @@ fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { #[cfg(test)] mod tests { - use super::*; - use crate::instruction::*; - use serial_test::serial; - use solana_program::{ - account_info::IntoAccountInfo, - clock::Epoch, - instruction::Instruction, - program_error::{self, PrintProgramError}, - sysvar::rent, - }; - use solana_sdk::account::{ - create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, + use { + super::*, + crate::instruction::*, + serial_test::serial, + solana_program::{ + account_info::IntoAccountInfo, + clock::Epoch, + instruction::Instruction, + program_error::{self, PrintProgramError}, + sysvar::rent, + }, + solana_sdk::account::{ + create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, + }, + std::sync::{Arc, RwLock}, }; - use std::sync::{Arc, RwLock}; lazy_static::lazy_static! { static ref EXPECTED_DATA: Arc>> = Arc::new(RwLock::new(Vec::new())); diff --git a/program/src/state.rs b/program/src/state.rs index 8723065..062daab 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -1,13 +1,15 @@ //! State transition types -use crate::instruction::MAX_SIGNERS; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use num_enum::TryFromPrimitive; -use solana_program::{ - program_error::ProgramError, - program_option::COption, - program_pack::{IsInitialized, Pack, Sealed}, - pubkey::{Pubkey, PUBKEY_BYTES}, +use { + crate::instruction::MAX_SIGNERS, + arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, + num_enum::TryFromPrimitive, + solana_program::{ + program_error::ProgramError, + program_option::COption, + program_pack::{IsInitialized, Pack, Sealed}, + pubkey::{Pubkey, PUBKEY_BYTES}, + }, }; /// Mint data. From 16946727389a68e9085b0a8305df6e834d5f1cec Mon Sep 17 00:00:00 2001 From: Joe C Date: Wed, 8 Nov 2023 20:41:36 +0000 Subject: [PATCH 218/335] rustfmt: format comments This PR adds comment formatting configurations to the repository's `rustfmt.toml` file, and the associated changes from `cargo +nightly fmt --all`. Comment width 80. --- program/src/instruction.rs | 56 +++++++++++++++++++++----------------- program/src/lib.rs | 21 ++++++++------ program/src/processor.rs | 18 ++++++++---- program/src/state.rs | 41 ++++++++++++++++------------ 4 files changed, 80 insertions(+), 56 deletions(-) diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 067fde5..ede7308 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -36,7 +36,6 @@ pub enum TokenInstruction<'a> { /// /// 0. `[writable]` The mint to initialize. /// 1. `[]` Rent sysvar - /// InitializeMint { /// Number of base 10 digits to the right of the decimal place. decimals: u8, @@ -352,10 +351,10 @@ pub enum TokenInstruction<'a> { /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, - /// Like InitializeAccount, but the owner pubkey is passed via instruction data - /// rather than the accounts list. This variant may be preferable when using - /// Cross Program Invocation from an instruction that does not need the owner's - /// `AccountInfo` otherwise. + /// Like InitializeAccount, but the owner pubkey is passed via instruction + /// data rather than the accounts list. This variant may be preferable + /// when using Cross Program Invocation from an instruction that does + /// not need the owner's `AccountInfo` otherwise. /// /// Accounts expected by this instruction: /// @@ -368,15 +367,17 @@ pub enum TokenInstruction<'a> { }, /// Given a wrapped / native token account (a token account containing SOL) /// updates its amount field based on the account's underlying `lamports`. - /// This is useful if a non-wrapped SOL account uses `system_instruction::transfer` - /// to move lamports to a wrapped token account, and needs to have its token - /// `amount` field updated. + /// This is useful if a non-wrapped SOL account uses + /// `system_instruction::transfer` to move lamports to a wrapped token + /// account, and needs to have its token `amount` field updated. /// /// Accounts expected by this instruction: /// - /// 0. `[writable]` The native token account to sync with its underlying lamports. + /// 0. `[writable]` The native token account to sync with its underlying + /// lamports. SyncNative, - /// Like InitializeAccount2, but does not require the Rent sysvar to be provided + /// Like InitializeAccount2, but does not require the Rent sysvar to be + /// provided /// /// Accounts expected by this instruction: /// @@ -386,7 +387,8 @@ pub enum TokenInstruction<'a> { /// The new account's owner/multisignature. owner: Pubkey, }, - /// Like InitializeMultisig, but does not require the Rent sysvar to be provided + /// Like InitializeMultisig, but does not require the Rent sysvar to be + /// provided /// /// Accounts expected by this instruction: /// @@ -398,12 +400,12 @@ pub enum TokenInstruction<'a> { /// account. m: u8, }, - /// Like [`InitializeMint`], but does not require the Rent sysvar to be provided + /// Like [`InitializeMint`], but does not require the Rent sysvar to be + /// provided /// /// Accounts expected by this instruction: /// /// 0. `[writable]` The mint to initialize. - /// InitializeMint2 { /// Number of base 10 digits to the right of the decimal place. decimals: u8, @@ -412,8 +414,8 @@ pub enum TokenInstruction<'a> { /// The freeze authority/multisignature of the mint. freeze_authority: COption, }, - /// Gets the required size of an account for the given mint as a little-endian - /// `u64`. + /// Gets the required size of an account for the given mint as a + /// little-endian `u64`. /// /// Return data can be fetched using `sol_get_return_data` and deserializing /// the return data as a little-endian `u64`. @@ -424,8 +426,8 @@ pub enum TokenInstruction<'a> { GetAccountDataSize, // typically, there's also data, but this program ignores it /// Initialize the Immutable Owner extension for the given token account /// - /// Fails if the account has already been initialized, so must be called before - /// `InitializeAccount`. + /// Fails if the account has already been initialized, so must be called + /// before `InitializeAccount`. /// /// No-ops in this version of the program, but is included for compatibility /// with the Associated Token Account program. @@ -437,13 +439,14 @@ pub enum TokenInstruction<'a> { /// Data expected by this instruction: /// None InitializeImmutableOwner, - /// Convert an Amount of tokens to a UiAmount `string`, using the given mint. - /// In this version of the program, the mint can only specify the number of decimals. + /// Convert an Amount of tokens to a UiAmount `string`, using the given + /// mint. In this version of the program, the mint can only specify the + /// number of decimals. /// /// Fails on an invalid mint. /// - /// Return data can be fetched using `sol_get_return_data` and deserialized with - /// `String::from_utf8`. + /// Return data can be fetched using `sol_get_return_data` and deserialized + /// with `String::from_utf8`. /// /// Accounts expected by this instruction: /// @@ -452,8 +455,9 @@ pub enum TokenInstruction<'a> { /// The amount of tokens to reformat. amount: u64, }, - /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using the given mint. - /// In this version of the program, the mint can only specify the number of decimals. + /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using + /// the given mint. In this version of the program, the mint can only + /// specify the number of decimals. /// /// Return data can be fetched using `sol_get_return_data` and deserializing /// the return data as a little-endian `u64`. @@ -470,7 +474,8 @@ pub enum TokenInstruction<'a> { // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility } impl<'a> TokenInstruction<'a> { - /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html). + /// Unpacks a byte buffer into a + /// [TokenInstruction](enum.TokenInstruction.html). pub fn unpack(input: &'a [u8]) -> Result { use TokenError::InvalidInstruction; @@ -574,7 +579,8 @@ impl<'a> TokenInstruction<'a> { }) } - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer. + /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte + /// buffer. pub fn pack(&self) -> Vec { let mut buf = Vec::with_capacity(size_of::()); match self { diff --git a/program/src/lib.rs b/program/src/lib.rs index 1eb3855..25175df 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -13,22 +13,25 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk version +// Export current sdk types for downstream users building with a different sdk +// version pub use solana_program; use solana_program::{entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey}; -/// Convert the UI representation of a token amount (using the decimals field defined in its mint) -/// to the raw amount +/// Convert the UI representation of a token amount (using the decimals field +/// defined in its mint) to the raw amount pub fn ui_amount_to_amount(ui_amount: f64, decimals: u8) -> u64 { (ui_amount * 10_usize.pow(decimals as u32) as f64) as u64 } -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +/// Convert a raw amount to its UI representation (using the decimals field +/// defined in its mint) pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 { amount as f64 / 10_usize.pow(decimals as u32) as f64 } -/// Convert a raw amount to its UI representation (using the decimals field defined in its mint) +/// Convert a raw amount to its UI representation (using the decimals field +/// defined in its mint) pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { let decimals = decimals as usize; if decimals > 0 { @@ -53,12 +56,14 @@ pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { s } -/// Try to convert a UI representation of a token amount to its raw amount using the given decimals -/// field +/// Try to convert a UI representation of a token amount to its raw amount using +/// the given decimals field pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { let decimals = decimals as usize; let mut parts = ui_amount.split('.'); - let mut amount_str = parts.next().unwrap().to_string(); // splitting a string, even an empty one, will always yield an iterator of at least length == 1 + // splitting a string, even an empty one, will always yield an iterator of + // at least length == 1 + let mut amount_str = parts.next().unwrap().to_string(); let after_decimal = parts.next().unwrap_or(""); let after_decimal = after_decimal.trim_end_matches('0'); if (amount_str.is_empty() && after_decimal.is_empty()) diff --git a/program/src/processor.rs b/program/src/processor.rs index a849382..550df44 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -141,7 +141,8 @@ impl Processor { Ok(()) } - /// Processes an [InitializeAccount](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account( program_id: &Pubkey, accounts: &[AccountInfo], @@ -149,7 +150,8 @@ impl Processor { Self::_process_initialize_account(program_id, accounts, None, true) } - /// Processes an [InitializeAccount2](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount2](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account2( program_id: &Pubkey, accounts: &[AccountInfo], @@ -158,7 +160,8 @@ impl Processor { Self::_process_initialize_account(program_id, accounts, Some(&owner), true) } - /// Processes an [InitializeAccount3](enum.TokenInstruction.html) instruction. + /// Processes an [InitializeAccount3](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_account3( program_id: &Pubkey, accounts: &[AccountInfo], @@ -209,12 +212,14 @@ impl Processor { Ok(()) } - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) instruction. + /// Processes a [InitializeMultisig](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { Self::_process_initialize_multisig(accounts, m, true) } - /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) instruction. + /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { Self::_process_initialize_multisig(accounts, m, false) } @@ -789,7 +794,8 @@ impl Processor { Ok(()) } - /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) instruction + /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) + /// instruction pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let token_account_info = next_account_info(account_info_iter)?; diff --git a/program/src/state.rs b/program/src/state.rs index 062daab..fe23fba 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -16,9 +16,10 @@ use { #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Mint { - /// Optional authority used to mint new tokens. The mint authority may only be provided during - /// mint creation. If no mint authority is present then the mint has a fixed supply and no - /// further tokens may be minted. + /// Optional authority used to mint new tokens. The mint authority may only + /// be provided during mint creation. If no mint authority is present + /// then the mint has a fixed supply and no further tokens may be + /// minted. pub mint_authority: COption, /// Total supply of tokens. pub supply: u64, @@ -97,9 +98,10 @@ pub struct Account { pub delegate: COption, /// The account's state pub state: AccountState, - /// If is_native.is_some, this is a native token, and the value logs the rent-exempt reserve. An - /// Account is required to be rent-exempt, so the value is used by the Processor to ensure that - /// wrapped SOL accounts do not drop below this threshold. + /// If is_native.is_some, this is a native token, and the value logs the + /// rent-exempt reserve. An Account is required to be rent-exempt, so + /// the value is used by the Processor to ensure that wrapped SOL + /// accounts do not drop below this threshold. pub is_native: COption, /// The amount delegated pub delegated_amount: u64, @@ -115,7 +117,8 @@ impl Account { pub fn is_native(&self) -> bool { self.is_native.is_some() } - /// Checks if a token Account's owner is the system_program or the incinerator + /// Checks if a token Account's owner is the system_program or the + /// incinerator pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { solana_program::system_program::check_id(&self.owner) || solana_program::incinerator::check_id(&self.owner) @@ -185,11 +188,12 @@ pub enum AccountState { /// Account is not yet initialized #[default] Uninitialized, - /// Account is initialized; the account owner and/or delegate may perform permitted operations - /// on this account + /// Account is initialized; the account owner and/or delegate may perform + /// permitted operations on this account Initialized, - /// Account has been frozen by the mint freeze authority. Neither the account owner nor - /// the delegate are able to perform operations on this account. + /// Account has been frozen by the mint freeze authority. Neither the + /// account owner nor the delegate are able to perform operations on + /// this account. Frozen, } @@ -292,24 +296,27 @@ fn unpack_coption_u64(src: &[u8; 12]) -> Result, ProgramError> { const SPL_TOKEN_ACCOUNT_MINT_OFFSET: usize = 0; const SPL_TOKEN_ACCOUNT_OWNER_OFFSET: usize = 32; -/// A trait for token Account structs to enable efficiently unpacking various fields -/// without unpacking the complete state. +/// A trait for token Account structs to enable efficiently unpacking various +/// fields without unpacking the complete state. pub trait GenericTokenAccount { /// Check if the account data is a valid token account fn valid_account_data(account_data: &[u8]) -> bool; - /// Call after account length has already been verified to unpack the account owner + /// Call after account length has already been verified to unpack the + /// account owner fn unpack_account_owner_unchecked(account_data: &[u8]) -> &Pubkey { Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_OWNER_OFFSET) } - /// Call after account length has already been verified to unpack the account mint + /// Call after account length has already been verified to unpack the + /// account mint fn unpack_account_mint_unchecked(account_data: &[u8]) -> &Pubkey { Self::unpack_pubkey_unchecked(account_data, SPL_TOKEN_ACCOUNT_MINT_OFFSET) } - /// Call after account length has already been verified to unpack a Pubkey at - /// the specified offset. Panics if `account_data.len()` is less than `PUBKEY_BYTES` + /// Call after account length has already been verified to unpack a Pubkey + /// at the specified offset. Panics if `account_data.len()` is less than + /// `PUBKEY_BYTES` fn unpack_pubkey_unchecked(account_data: &[u8], offset: usize) -> &Pubkey { bytemuck::from_bytes(&account_data[offset..offset + PUBKEY_BYTES]) } From 867c869f0140574cea2a2e2c94b76c522d13a71f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:55:40 +0100 Subject: [PATCH 219/335] build(deps): bump proptest from 1.3.1 to 1.4.0 (#5812) Bumps [proptest](https://github.com/proptest-rs/proptest) from 1.3.1 to 1.4.0. - [Release notes](https://github.com/proptest-rs/proptest/releases) - [Changelog](https://github.com/proptest-rs/proptest/blob/master/CHANGELOG.md) - [Commits](https://github.com/proptest-rs/proptest/compare/v1.3.1...v1.4.0) --- updated-dependencies: - dependency-name: proptest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 17c1b4d..a8ec01b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -23,7 +23,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" -proptest = "1.3" +proptest = "1.4" serial_test = "2.0.0" solana-program-test = "1.17.2" solana-sdk = "1.17.2" From 7863cdab9db4d9e1405004113b23daf674937495 Mon Sep 17 00:00:00 2001 From: Jon Cinque Date: Wed, 29 Nov 2023 12:55:07 +0100 Subject: [PATCH 220/335] repo: Update to 1.17.6 (#5863) * repo: Update to 1.17.6 with script * Update lockfile * Remove disabling feature in token-cli tests --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index a8ec01b..ca9207a 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.14.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.1" -solana-program = "1.17.2" +solana-program = "1.17.6" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" serial_test = "2.0.0" -solana-program-test = "1.17.2" -solana-sdk = "1.17.2" +solana-program-test = "1.17.6" +solana-sdk = "1.17.6" [lib] crate-type = ["cdylib", "lib"] From 57e8d2f64ee12e791516a85fb01b8d1fe478a2fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:02:56 +0100 Subject: [PATCH 221/335] build(deps): bump num_enum from 0.7.1 to 0.7.2 (#6072) Bumps [num_enum](https://github.com/illicitonion/num_enum) from 0.7.1 to 0.7.2. - [Commits](https://github.com/illicitonion/num_enum/compare/0.7.1...0.7.2) --- updated-dependencies: - dependency-name: num_enum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index ca9207a..0ffa2f1 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,7 +17,7 @@ arrayref = "0.3.7" bytemuck = "1.14.0" num-derive = "0.4" num-traits = "0.2" -num_enum = "0.7.1" +num_enum = "0.7.2" solana-program = "1.17.6" thiserror = "1.0" From b6f489fd7ef254f48a96c041b9e25a5d73b6e27d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:56:47 +0100 Subject: [PATCH 222/335] build(deps): bump serial_test from 2.0.0 to 3.0.0 (#6073) Bumps [serial_test](https://github.com/palfrey/serial_test) from 2.0.0 to 3.0.0. - [Release notes](https://github.com/palfrey/serial_test/releases) - [Commits](https://github.com/palfrey/serial_test/compare/v2.0.0...v3.0.0) --- updated-dependencies: - dependency-name: serial_test dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 0ffa2f1..1131aa2 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -24,7 +24,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" -serial_test = "2.0.0" +serial_test = "3.0.0" solana-program-test = "1.17.6" solana-sdk = "1.17.6" From ab84b656825de4d9c78c14e1d82d5ad23b27a753 Mon Sep 17 00:00:00 2001 From: Emanuele Cesena Date: Wed, 17 Jan 2024 17:03:22 -0800 Subject: [PATCH 223/335] token 2022: upgrade sdk to 1.17.13 (#6147) * token 2022: upgrade sdk to 1.17.13 * Upgrade all remaining packages --------- Co-authored-by: Jon C --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 1131aa2..6aca0f2 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.14.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" -solana-program = "1.17.6" +solana-program = "1.17.13" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" serial_test = "3.0.0" -solana-program-test = "1.17.6" -solana-sdk = "1.17.6" +solana-program-test = "1.17.13" +solana-sdk = "1.17.13" [lib] crate-type = ["cdylib", "lib"] From fc53ce524b8f0e54ab9f694dfe764413c8889219 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:58:50 +0100 Subject: [PATCH 224/335] build(deps): bump bytemuck from 1.14.0 to 1.14.1 (#6179) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.14.0 to 1.14.1. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.14.0...v1.14.1) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 6aca0f2..c72c9a0 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" -bytemuck = "1.14.0" +bytemuck = "1.14.1" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" From 8ced6b803f5c51fd8a34e3d9a6f1783f4d451cf7 Mon Sep 17 00:00:00 2001 From: Will Hickey Date: Fri, 26 Jan 2024 15:31:55 -0600 Subject: [PATCH 225/335] Update solana dependency version to allow 2.0.0 (#6182) * Update solana dependency version to allow 2.0.0 * Fix version number in solana-version.sh * Fix version numbers * Revert solana-version.sh with note * Revert Anchor version change * Relax dependency version upper bound to 2 --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index c72c9a0..7c5c43d 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.14.1" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" -solana-program = "1.17.13" +solana-program = ">=1.17.13,<=2" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" serial_test = "3.0.0" -solana-program-test = "1.17.13" -solana-sdk = "1.17.13" +solana-program-test = ">=1.17.13,<=2" +solana-sdk = ">=1.17.13,<=2" [lib] crate-type = ["cdylib", "lib"] From 4305db744910bfbfa2c54fafc0b9f7ca2fa5a889 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 1 Feb 2024 10:09:45 +0900 Subject: [PATCH 226/335] Upgrade to solana 1.17.17 (#6189) * upgrade to solana version 1.17.17 * add display for the group extensions * upgrade to solana version 1.17.17 * update cargo lock --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 7c5c43d..012e97d 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.14.1" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" -solana-program = ">=1.17.13,<=2" +solana-program = ">=1.17.17,<=2" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" serial_test = "3.0.0" -solana-program-test = ">=1.17.13,<=2" -solana-sdk = ">=1.17.13,<=2" +solana-program-test = ">=1.17.17,<=2" +solana-sdk = ">=1.17.17,<=2" [lib] crate-type = ["cdylib", "lib"] From afaa8e1c433e5c60d56d214d2a4b6744196d2ede Mon Sep 17 00:00:00 2001 From: Will Hickey Date: Mon, 5 Feb 2024 14:52:18 -0600 Subject: [PATCH 227/335] Bump SPL crate versions (#6221) * Update associated-token-account version to 2.3.1 * Update discriminator version to 0.1.1 * Update discriminator-derive version to 0.1.2 * Update discriminator-syn version to 0.1.2 * Update instruction-padding version to 0.1.1 * Update memo version to 4.0.1 * Update pod version to 0.1.1 * Update program-error version to 0.3.1 * Update program-error-derive version to 0.3.2 * Update tlv-account-resolution version to 0.5.2 * Update token version to 4.0.1 * Cargo.lock * Update token-group-interface version to 0.1.1 * Update token-metadata-interface version to 0.2.1 * Update transfer-hook-interface version to 0.5.1 * Update type-length-value version to 0.3.1 * Cargo.lock * Remove extraneous whitespace --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 012e97d..2961ad4 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "4.0.0" +version = "4.0.1" description = "Solana Program Library Token" authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From b27bc975f0c7758a59c42cc35f2fb791002171b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:03:05 -0500 Subject: [PATCH 228/335] build(deps): bump bytemuck from 1.14.1 to 1.14.2 (#6231) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.14.1 to 1.14.2. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.14.1...v1.14.2) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 2961ad4..68f6653 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" -bytemuck = "1.14.1" +bytemuck = "1.14.2" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" From 3181ab1a0b0a02968c17214f7d08b08ae0e54bd0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 19:01:35 -0500 Subject: [PATCH 229/335] build(deps): bump bytemuck from 1.14.2 to 1.14.3 (#6240) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.14.2 to 1.14.3. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.14.2...v1.14.3) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 68f6653..4636f5c 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" -bytemuck = "1.14.2" +bytemuck = "1.14.3" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" From 5ccb919ed0d939c8f124b1eedc53df3f6ab66469 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 29 Feb 2024 10:06:27 +0900 Subject: [PATCH 230/335] Upgrade to Solana 1.18.2 (#6278) * upgrade to solana 1.18.2 * upgrade rust version to 1.76.0 * update borsh to 1.2.1 * replace deprecated `try_to_vec` with `borsh::to_vec` * temporarily allow deprecated functions in cli that uses clap-v3 * use `repr(u32)` for enums in token lending --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 4636f5c..8f9a059 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.14.3" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" -solana-program = ">=1.17.17,<=2" +solana-program = ">=1.18.2,<=2" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" serial_test = "3.0.0" -solana-program-test = ">=1.17.17,<=2" -solana-sdk = ">=1.17.17,<=2" +solana-program-test = ">=1.18.2,<=2" +solana-sdk = ">=1.18.2,<=2" [lib] crate-type = ["cdylib", "lib"] From a907a145efca443d0a55d0af8b05ace0d459f2ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 12:38:01 +0100 Subject: [PATCH 231/335] build(deps): bump bytemuck from 1.14.3 to 1.15.0 (#6415) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.14.3 to 1.15.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.14.3...v1.15.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 8f9a059..90f6941 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" -bytemuck = "1.14.3" +bytemuck = "1.15.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" From b7912c191b200ac2cd5c2ce85e44a2974a8e370b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 13:26:59 +0200 Subject: [PATCH 232/335] build(deps): bump serial_test from 3.0.0 to 3.1.0 (#6606) Bumps [serial_test](https://github.com/palfrey/serial_test) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/palfrey/serial_test/releases) - [Commits](https://github.com/palfrey/serial_test/compare/v3.0.0...v3.1.0) --- updated-dependencies: - dependency-name: serial_test dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 90f6941..47053b9 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -24,7 +24,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" -serial_test = "3.0.0" +serial_test = "3.1.0" solana-program-test = ">=1.18.2,<=2" solana-sdk = ">=1.18.2,<=2" From 044d44805de199d7d098cf94b6944dd717355e82 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Wed, 24 Apr 2024 12:01:47 +0900 Subject: [PATCH 233/335] Bump solana version to 1.18.11 (#6624) upgrade solana version to 1.18.11 --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 47053b9..afa5627 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.15.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" -solana-program = ">=1.18.2,<=2" +solana-program = ">=1.18.11,<=2" thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" serial_test = "3.1.0" -solana-program-test = ">=1.18.2,<=2" -solana-sdk = ">=1.18.2,<=2" +solana-program-test = ">=1.18.11,<=2" +solana-sdk = ">=1.18.11,<=2" [lib] crate-type = ["cdylib", "lib"] From 00477178446f11efeff8445bd6ee7d079838d596 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:51:53 +0200 Subject: [PATCH 234/335] build(deps): bump serial_test from 3.1.0 to 3.1.1 (#6649) Bumps [serial_test](https://github.com/palfrey/serial_test) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/palfrey/serial_test/releases) - [Commits](https://github.com/palfrey/serial_test/compare/v3.1.0...v3.1.1) --- updated-dependencies: - dependency-name: serial_test dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index afa5627..e310bf3 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -24,7 +24,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" proptest = "1.4" -serial_test = "3.1.0" +serial_test = "3.1.1" solana-program-test = ">=1.18.11,<=2" solana-sdk = ">=1.18.11,<=2" From aac6bbba9b3dcc63be532114c0c86d204609c139 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 22:20:09 +0200 Subject: [PATCH 235/335] build(deps): bump bytemuck from 1.15.0 to 1.16.0 (#6729) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.15.0 to 1.16.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.15.0...v1.16.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index e310bf3..1ff5b08 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" -bytemuck = "1.15.0" +bytemuck = "1.16.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" From 53f27c16d5ed5cab1753d11bc49212d58f84f6e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:04:54 +0200 Subject: [PATCH 236/335] build(deps): bump bytemuck from 1.16.0 to 1.16.1 (#6875) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.16.0 to 1.16.1. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.16.0...v1.16.1) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 1ff5b08..07f8803 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.7" -bytemuck = "1.16.0" +bytemuck = "1.16.1" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" From 63429e3755b98ca086cfabfc77b4aa3f8e635251 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:29:48 +0200 Subject: [PATCH 237/335] build(deps): bump proptest from 1.4.0 to 1.5.0 (#6899) Bumps [proptest](https://github.com/proptest-rs/proptest) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/proptest-rs/proptest/releases) - [Changelog](https://github.com/proptest-rs/proptest/blob/master/CHANGELOG.md) - [Commits](https://github.com/proptest-rs/proptest/compare/v1.4.0...v1.5.0) --- updated-dependencies: - dependency-name: proptest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 07f8803..a8c3101 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -23,7 +23,7 @@ thiserror = "1.0" [dev-dependencies] lazy_static = "1.4.0" -proptest = "1.4" +proptest = "1.5" serial_test = "3.1.1" solana-program-test = ">=1.18.11,<=2" solana-sdk = ">=1.18.11,<=2" From 2837b4ce6cc1e71b4a5a140caf6118e103166dd7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:59:52 +0200 Subject: [PATCH 238/335] build(deps): bump lazy_static from 1.4.0 to 1.5.0 (#6900) Bumps [lazy_static](https://github.com/rust-lang-nursery/lazy-static.rs) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/rust-lang-nursery/lazy-static.rs/releases) - [Commits](https://github.com/rust-lang-nursery/lazy-static.rs/compare/1.4.0...1.5.0) --- updated-dependencies: - dependency-name: lazy_static dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index a8c3101..16a99e1 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -22,7 +22,7 @@ solana-program = ">=1.18.11,<=2" thiserror = "1.0" [dev-dependencies] -lazy_static = "1.4.0" +lazy_static = "1.5.0" proptest = "1.5" serial_test = "3.1.1" solana-program-test = ">=1.18.11,<=2" From 76461efd03171c19169084a5e23df14ce031d015 Mon Sep 17 00:00:00 2001 From: Jon C Date: Mon, 24 Jun 2024 14:37:09 +0200 Subject: [PATCH 239/335] token: Update to v5 for solana-program 2.0 compatibility (#6907) Updating to allow for version <= 2.0 of the solana crates can appear as a breaking change for new projects, since cargo pulls in the latest version of all dependencies, and once there's an attempt to mix v1 and v2, downstream users will see errors. This is made worse that the patch versions will quietly pick up the v2 dependency, so if someone doesn't know how to manipulate a cargo lockfile, they will get build errors and won't know how to resolve them. All other SPL crates contain a new breaking version (new major for crates on v1 or more, new minor for crates on v0.X), except for spl-token. Bump spl-token to v5. --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 16a99e1..c4336be 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "4.0.1" +version = "5.0.0" description = "Solana Program Library Token" authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From b4a8f7fac77e536f3d277bf7ed2f19a2732a7bbc Mon Sep 17 00:00:00 2001 From: Jon C Date: Tue, 25 Jun 2024 11:11:23 +0200 Subject: [PATCH 240/335] deps: Upgrade to Solana v2 (#6908) * solana: Update deps to 2.0.0 * Update lockfile * Update toolchain version * Update nightly version * Fix check issues * Fix clippy * Revert upgrade for account compression libs * Install build deps for serde test * Fixup versions * Fixup twoxtx build * Revert solana install version * Actually, get version 2.0.0 from the correct place --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index c4336be..ffc5c1b 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.16.1" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" -solana-program = ">=1.18.11,<=2" +solana-program = "2.0.0" thiserror = "1.0" [dev-dependencies] lazy_static = "1.5.0" proptest = "1.5" serial_test = "3.1.1" -solana-program-test = ">=1.18.11,<=2" -solana-sdk = ">=1.18.11,<=2" +solana-program-test = "2.0.0" +solana-sdk = "2.0.0" [lib] crate-type = ["cdylib", "lib"] From 92c3ca9f0e51c5f30c77ff1a67b6fae859d0866e Mon Sep 17 00:00:00 2001 From: Jon C Date: Tue, 25 Jun 2024 13:17:22 +0200 Subject: [PATCH 241/335] token: Bump to v6 for Solana v2 compatibility (#6918) --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index ffc5c1b..a375400 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "5.0.0" +version = "6.0.0" description = "Solana Program Library Token" authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From ade6e49d816305401fc295b63041eabfa22ee3fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 13:14:12 +0200 Subject: [PATCH 242/335] build(deps): bump arrayref from 0.3.7 to 0.3.8 (#7034) Bumps [arrayref](https://github.com/droundy/arrayref) from 0.3.7 to 0.3.8. - [Commits](https://github.com/droundy/arrayref/commits) --- updated-dependencies: - dependency-name: arrayref dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index a375400..077bdfe 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -13,7 +13,7 @@ no-entrypoint = [] test-sbf = [] [dependencies] -arrayref = "0.3.7" +arrayref = "0.3.8" bytemuck = "1.16.1" num-derive = "0.4" num-traits = "0.2" From 35bf5154df99cb43550f188cda6adb4d7540e705 Mon Sep 17 00:00:00 2001 From: Jon C Date: Thu, 25 Jul 2024 16:53:13 +0200 Subject: [PATCH 243/335] ci: Bump crates to Solana 2.0.3 (#7047) * Run script * Update lockfile * Use "processed" instead of deprecated "recent" * Fixup account compression tests * account-compression: Remove `only` in test --- program/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 077bdfe..fbc2575 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,15 +18,15 @@ bytemuck = "1.16.1" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.2" -solana-program = "2.0.0" +solana-program = "2.0.3" thiserror = "1.0" [dev-dependencies] lazy_static = "1.5.0" proptest = "1.5" serial_test = "3.1.1" -solana-program-test = "2.0.0" -solana-sdk = "2.0.0" +solana-program-test = "2.0.3" +solana-sdk = "2.0.3" [lib] crate-type = ["cdylib", "lib"] From 4f267d1f3d7a0cf5fb7bce93572ce47cf176ddb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 11:33:42 +0200 Subject: [PATCH 244/335] build(deps): bump num_enum from 0.7.2 to 0.7.3 (#7071) Bumps [num_enum](https://github.com/illicitonion/num_enum) from 0.7.2 to 0.7.3. - [Commits](https://github.com/illicitonion/num_enum/compare/0.7.2...0.7.3) --- updated-dependencies: - dependency-name: num_enum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index fbc2575..183e081 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,7 +17,7 @@ arrayref = "0.3.8" bytemuck = "1.16.1" num-derive = "0.4" num-traits = "0.2" -num_enum = "0.7.2" +num_enum = "0.7.3" solana-program = "2.0.3" thiserror = "1.0" From e0f13ce18f062a309593dffae72876e7a7c5d7d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 11:36:08 +0200 Subject: [PATCH 245/335] build(deps): bump bytemuck from 1.16.1 to 1.16.3 (#7077) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.16.1 to 1.16.3. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.16.1...v1.16.3) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 183e081..2c46629 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.8" -bytemuck = "1.16.1" +bytemuck = "1.16.3" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" From 4fc1f5346c8b768a57bb70ef40f013de6c09f29a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Aug 2024 08:48:26 -0400 Subject: [PATCH 246/335] build(deps): bump bytemuck from 1.16.3 to 1.17.0 (#7159) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.16.3 to 1.17.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.16.3...v1.17.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 2c46629..50d5de2 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.8" -bytemuck = "1.16.3" +bytemuck = "1.17.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" From e81637afbdfd9d5bc5f13e8c4a8bfa2478bf92b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:46:28 +0200 Subject: [PATCH 247/335] build(deps): bump bytemuck from 1.17.0 to 1.17.1 (#7209) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.17.0 to 1.17.1. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.17.0...v1.17.1) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 50d5de2..7276e2f 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.8" -bytemuck = "1.17.0" +bytemuck = "1.17.1" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" From 91940fe2d822c806377a069cea6d0c85f587152e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:27:55 +0200 Subject: [PATCH 248/335] build(deps): bump bytemuck from 1.17.1 to 1.18.0 (#7244) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.17.1 to 1.18.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.17.1...v1.18.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 7276e2f..f3e3658 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.8" -bytemuck = "1.17.1" +bytemuck = "1.18.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" From b6e3c5b5efad20a7c54c0088c6006495e0e46cd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 00:38:10 +0800 Subject: [PATCH 249/335] build(deps): bump arrayref from 0.3.8 to 0.3.9 (#7278) Bumps [arrayref](https://github.com/droundy/arrayref) from 0.3.8 to 0.3.9. - [Commits](https://github.com/droundy/arrayref/commits) --- updated-dependencies: - dependency-name: arrayref dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index f3e3658..a912314 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -13,7 +13,7 @@ no-entrypoint = [] test-sbf = [] [dependencies] -arrayref = "0.3.8" +arrayref = "0.3.9" bytemuck = "1.18.0" num-derive = "0.4" num-traits = "0.2" From e9c4885e190a1e8be45adfa89b649a955dd561ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:59:51 +0200 Subject: [PATCH 250/335] build(deps): bump bytemuck from 1.18.0 to 1.19.0 (#7345) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.18.0 to 1.19.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.18.0...v1.19.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index a912314..67b92f3 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.9" -bytemuck = "1.18.0" +bytemuck = "1.19.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" From 37f4247c6ddf826b22b301523858cc2fb3583b07 Mon Sep 17 00:00:00 2001 From: Jon C Date: Thu, 31 Oct 2024 12:25:30 +0100 Subject: [PATCH 251/335] CI: Update to Solana v2.1 crates (#7416) * Run update script, update curve25519-dalek dep, rust * Run clippy + fmt * Add workspace lints, start fixing doc comments * Update doc comments for clippy * Re-run cargo fmt after doc comment update * Update solana-version * Update CI jobs --- program/Cargo.toml | 9 ++++++--- program/tests/assert_instruction_count.rs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 67b92f3..3b363fb 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -18,18 +18,21 @@ bytemuck = "1.19.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" -solana-program = "2.0.3" +solana-program = "2.1.0" thiserror = "1.0" [dev-dependencies] lazy_static = "1.5.0" proptest = "1.5" serial_test = "3.1.1" -solana-program-test = "2.0.3" -solana-sdk = "2.0.3" +solana-program-test = "2.1.0" +solana-sdk = "2.1.0" [lib] crate-type = ["cdylib", "lib"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] + +[lints] +workspace = true diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs index a6df337..009fb1e 100644 --- a/program/tests/assert_instruction_count.rs +++ b/program/tests/assert_instruction_count.rs @@ -23,7 +23,7 @@ const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; async fn initialize_mint() { let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); pt.set_compute_max_units(5_000); // last known 2252 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; + let (banks_client, payer, recent_blockhash) = pt.start().await; let owner_key = Pubkey::new_unique(); let mint = Keypair::new(); From a369f2cbfb9af4c7af22f26541cb4a841b2643ce Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:31:50 +0000 Subject: [PATCH 252/335] Publish spl-token v7.0.0 --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 3b363fb..c424044 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "6.0.0" +version = "7.0.0" description = "Solana Program Library Token" authors = ["Solana Labs Maintainers "] repository = "https://github.com/solana-labs/solana-program-library" From e50c07bb9aefffef2afdb5fd0aedab58c64b067e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 11:44:32 +0100 Subject: [PATCH 253/335] build(deps): bump thiserror from 1.0.68 to 2.0.0 (#7462) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.68 to 2.0.0. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.68...2.0.0) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index c424044..c336eda 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -19,7 +19,7 @@ num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" solana-program = "2.1.0" -thiserror = "1.0" +thiserror = "2.0" [dev-dependencies] lazy_static = "1.5.0" From 00eadc670e1fb59f549651ea4a448edec30d2c33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:21:44 +0100 Subject: [PATCH 254/335] build(deps): bump serial_test from 3.1.1 to 3.2.0 (#7481) Bumps [serial_test](https://github.com/palfrey/serial_test) from 3.1.1 to 3.2.0. - [Release notes](https://github.com/palfrey/serial_test/releases) - [Commits](https://github.com/palfrey/serial_test/compare/v3.1.1...v3.2.0) --- updated-dependencies: - dependency-name: serial_test dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index c336eda..93aea49 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -24,7 +24,7 @@ thiserror = "2.0" [dev-dependencies] lazy_static = "1.5.0" proptest = "1.5" -serial_test = "3.1.1" +serial_test = "3.2.0" solana-program-test = "2.1.0" solana-sdk = "2.1.0" From d4adbd3b4b29becb28e4abd23d241b08db82af39 Mon Sep 17 00:00:00 2001 From: Jon C Date: Mon, 18 Nov 2024 23:23:54 +0100 Subject: [PATCH 255/335] token: Fix typos for cargo-spellcheck (#7503) * token: Fix typos #### Problem There are typos in the token code, and people sometimes fix them, but mostly don't. #### Summary of changes Starting with the `token/*` directory, fix all typos or properly put them between backticks if they're code. These were all found using `cargo spellcheck` and a specialized dictionary with programming / Solana / ZK terminology. Once all of the typos are fixed, then we can add the spellchecking to CI. * Update doctests --- program/README.md | 2 +- program/src/instruction.rs | 75 +++++++++++++++++++------------------- program/src/native_mint.rs | 2 +- program/src/processor.rs | 48 +++++++++++++----------- program/src/state.rs | 6 +-- 5 files changed, 69 insertions(+), 64 deletions(-) diff --git a/program/README.md b/program/README.md index 02cbb7c..81167bf 100644 --- a/program/README.md +++ b/program/README.md @@ -5,7 +5,7 @@ A token program on the Solana blockchain, usable for fungible and non-fungible t This program provides an interface and implementation that third parties can utilize to create and use their tokens. -Full documentation is available at https://spl.solana.com/token +Full documentation is available at the [SPL Token docs](https://spl.solana.com/token). ## Audit diff --git a/program/src/instruction.rs b/program/src/instruction.rs index ede7308..b797a7d 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -16,7 +16,7 @@ use { pub const MIN_SIGNERS: usize = 1; /// Maximum number of multisignature signers (max N) pub const MAX_SIGNERS: usize = 11; -/// Serialized length of a u64, for unpacking +/// Serialized length of a `u64`, for unpacking const U64_BYTES: usize = 8; /// Instructions supported by the token program. @@ -80,8 +80,8 @@ pub enum TokenInstruction<'a> { /// /// 0. `[writable]` The multisignature account to initialize. /// 1. `[]` Rent sysvar - /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= - /// 11. + /// 2. ..`2+N`. `[]` The signer accounts, must equal to N where `1 <= N <= + /// 11`. InitializeMultisig { /// The number of signers (M) required to validate this multisignature /// account. @@ -103,7 +103,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The source account. /// 1. `[writable]` The destination account. /// 2. `[]` The source account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. ..`3+M` `[signer]` M signer accounts. Transfer { /// The amount of tokens to transfer. amount: u64, @@ -122,7 +122,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The source account. /// 1. `[]` The delegate. /// 2. `[]` The source account's multisignature owner. - /// 3. ..3+M `[signer]` M signer accounts + /// 3. ..`3+M` `[signer]` M signer accounts Approve { /// The amount of tokens the delegate is approved for. amount: u64, @@ -138,7 +138,7 @@ pub enum TokenInstruction<'a> { /// * Multisignature owner /// 0. `[writable]` The source account. /// 1. `[]` The source account's multisignature owner. - /// 2. ..2+M `[signer]` M signer accounts + /// 2. ..`2+M` `[signer]` M signer accounts Revoke, /// Sets a new authority of a mint or account. /// @@ -151,7 +151,7 @@ pub enum TokenInstruction<'a> { /// * Multisignature authority /// 0. `[writable]` The mint or account to change the authority of. /// 1. `[]` The mint's or account's current multisignature authority. - /// 2. ..2+M `[signer]` M signer accounts + /// 2. ..`2+M` `[signer]` M signer accounts SetAuthority { /// The type of authority to update. authority_type: AuthorityType, @@ -172,7 +172,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The mint. /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. ..`3+M` `[signer]` M signer accounts. MintTo { /// The amount of new tokens to mint. amount: u64, @@ -191,7 +191,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to burn from. /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. ..`3+M` `[signer]` M signer accounts. Burn { /// The amount of tokens to burn. amount: u64, @@ -210,9 +210,9 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to close. /// 1. `[writable]` The destination account. /// 2. `[]` The account's multisignature owner. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. ..`3+M` `[signer]` M signer accounts. CloseAccount, - /// Freeze an Initialized account using the Mint's freeze_authority (if + /// Freeze an Initialized account using the Mint's `freeze_authority` (if /// set). /// /// Accounts expected by this instruction: @@ -226,9 +226,9 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to freeze. /// 1. `[]` The token mint. /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. ..`3+M` `[signer]` M signer accounts. FreezeAccount, - /// Thaw a Frozen account using the Mint's freeze_authority (if set). + /// Thaw a Frozen account using the Mint's `freeze_authority` (if set). /// /// Accounts expected by this instruction: /// @@ -241,7 +241,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to freeze. /// 1. `[]` The token mint. /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. ..`3+M` `[signer]` M signer accounts. ThawAccount, /// Transfers tokens from one account to another either directly or via a @@ -266,7 +266,7 @@ pub enum TokenInstruction<'a> { /// 1. `[]` The token mint. /// 2. `[writable]` The destination account. /// 3. `[]` The source account's multisignature owner/delegate. - /// 4. ..4+M `[signer]` M signer accounts. + /// 4. ..`4+M` `[signer]` M signer accounts. TransferChecked { /// The amount of tokens to transfer. amount: u64, @@ -293,7 +293,7 @@ pub enum TokenInstruction<'a> { /// 1. `[]` The token mint. /// 2. `[]` The delegate. /// 3. `[]` The source account's multisignature owner. - /// 4. ..4+M `[signer]` M signer accounts + /// 4. ..`4+M` `[signer]` M signer accounts ApproveChecked { /// The amount of tokens the delegate is approved for. amount: u64, @@ -303,8 +303,8 @@ pub enum TokenInstruction<'a> { /// Mints new tokens to an account. The native mint does not support /// minting. /// - /// This instruction differs from MintTo in that the decimals value is - /// checked by the caller. This may be useful when creating transactions + /// This instruction differs from `MintTo` in that the decimals value is + /// checked by the caller. This may be useful when creating transactions /// offline or within a hardware wallet. /// /// Accounts expected by this instruction: @@ -318,7 +318,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The mint. /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. ..`3+M` `[signer]` M signer accounts. MintToChecked { /// The amount of new tokens to mint. amount: u64, @@ -344,17 +344,17 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to burn from. /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. ..`3+M` `[signer]` M signer accounts. BurnChecked { /// The amount of tokens to burn. amount: u64, /// Expected number of base 10 digits to the right of the decimal place. decimals: u8, }, - /// Like InitializeAccount, but the owner pubkey is passed via instruction - /// data rather than the accounts list. This variant may be preferable - /// when using Cross Program Invocation from an instruction that does - /// not need the owner's `AccountInfo` otherwise. + /// Like [`InitializeAccount`], but the owner pubkey is passed via + /// instruction data rather than the accounts list. This variant may be + /// preferable when using Cross Program Invocation from an instruction + /// that does not need the owner's `AccountInfo` otherwise. /// /// Accounts expected by this instruction: /// @@ -376,7 +376,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The native token account to sync with its underlying /// lamports. SyncNative, - /// Like InitializeAccount2, but does not require the Rent sysvar to be + /// Like [`InitializeAccount2`], but does not require the Rent sysvar to be /// provided /// /// Accounts expected by this instruction: @@ -387,14 +387,14 @@ pub enum TokenInstruction<'a> { /// The new account's owner/multisignature. owner: Pubkey, }, - /// Like InitializeMultisig, but does not require the Rent sysvar to be + /// Like [`InitializeMultisig`], but does not require the Rent sysvar to be /// provided /// /// Accounts expected by this instruction: /// /// 0. `[writable]` The multisignature account to initialize. - /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= - /// 11. + /// 1. ..`1+N` `[]` The signer accounts, must equal to N where `1 <= N <= + /// 11`. InitializeMultisig2 { /// The number of signers (M) required to validate this multisignature /// account. @@ -439,7 +439,7 @@ pub enum TokenInstruction<'a> { /// Data expected by this instruction: /// None InitializeImmutableOwner, - /// Convert an Amount of tokens to a UiAmount `string`, using the given + /// Convert an Amount of tokens to a `UiAmount` string, using the given /// mint. In this version of the program, the mint can only specify the /// number of decimals. /// @@ -455,9 +455,9 @@ pub enum TokenInstruction<'a> { /// The amount of tokens to reformat. amount: u64, }, - /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using - /// the given mint. In this version of the program, the mint can only - /// specify the number of decimals. + /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount, + /// using the given mint. In this version of the program, the mint can + /// only specify the number of decimals. /// /// Return data can be fetched using `sol_get_return_data` and deserializing /// the return data as a little-endian `u64`. @@ -466,7 +466,7 @@ pub enum TokenInstruction<'a> { /// /// 0. `[]` The mint to calculate for UiAmountToAmount { - /// The ui_amount of tokens to reformat. + /// The `ui_amount` of tokens to reformat. ui_amount: &'a str, }, // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the @@ -475,7 +475,7 @@ pub enum TokenInstruction<'a> { } impl<'a> TokenInstruction<'a> { /// Unpacks a byte buffer into a - /// [TokenInstruction](enum.TokenInstruction.html). + /// [`TokenInstruction`](enum.TokenInstruction.html). pub fn unpack(input: &'a [u8]) -> Result { use TokenError::InvalidInstruction; @@ -579,7 +579,7 @@ impl<'a> TokenInstruction<'a> { }) } - /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte + /// Packs a [`TokenInstruction`](enum.TokenInstruction.html) into a byte /// buffer. pub fn pack(&self) -> Vec { let mut buf = Vec::with_capacity(size_of::()); @@ -738,7 +738,7 @@ impl<'a> TokenInstruction<'a> { } } -/// Specifies the authority type for SetAuthority instructions +/// Specifies the authority type for `SetAuthority` instructions #[repr(u8)] #[derive(Clone, Debug, PartialEq)] pub enum AuthorityType { @@ -1431,7 +1431,8 @@ pub fn ui_amount_to_amount( }) } -/// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS +/// Utility function that checks index is between `MIN_SIGNERS` and +/// `MAX_SIGNERS` pub fn is_valid_signer_index(index: usize) -> bool { (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) } diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs index 37f7555..bd489ee 100644 --- a/program/src/native_mint.rs +++ b/program/src/native_mint.rs @@ -1,6 +1,6 @@ //! The Mint that represents the native token -/// There are 10^9 lamports in one SOL +/// There are `10^9` lamports in one SOL pub const DECIMALS: u8 = 9; // The Mint for native SOL Token accounts diff --git a/program/src/processor.rs b/program/src/processor.rs index 550df44..4702693 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -61,7 +61,7 @@ impl Processor { Ok(()) } - /// Processes an [InitializeMint](enum.TokenInstruction.html) instruction. + /// Processes an [`InitializeMint`](enum.TokenInstruction.html) instruction. pub fn process_initialize_mint( accounts: &[AccountInfo], decimals: u8, @@ -71,7 +71,8 @@ impl Processor { Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, true) } - /// Processes an [InitializeMint2](enum.TokenInstruction.html) instruction. + /// Processes an [`InitializeMint2`](enum.TokenInstruction.html) + /// instruction. pub fn process_initialize_mint2( accounts: &[AccountInfo], decimals: u8, @@ -141,7 +142,7 @@ impl Processor { Ok(()) } - /// Processes an [InitializeAccount](enum.TokenInstruction.html) + /// Processes an [`InitializeAccount`](enum.TokenInstruction.html) /// instruction. pub fn process_initialize_account( program_id: &Pubkey, @@ -150,7 +151,7 @@ impl Processor { Self::_process_initialize_account(program_id, accounts, None, true) } - /// Processes an [InitializeAccount2](enum.TokenInstruction.html) + /// Processes an [`InitializeAccount2`](enum.TokenInstruction.html) /// instruction. pub fn process_initialize_account2( program_id: &Pubkey, @@ -160,7 +161,7 @@ impl Processor { Self::_process_initialize_account(program_id, accounts, Some(&owner), true) } - /// Processes an [InitializeAccount3](enum.TokenInstruction.html) + /// Processes an [`InitializeAccount3`](enum.TokenInstruction.html) /// instruction. pub fn process_initialize_account3( program_id: &Pubkey, @@ -212,19 +213,19 @@ impl Processor { Ok(()) } - /// Processes a [InitializeMultisig](enum.TokenInstruction.html) + /// Processes a [`InitializeMultisig`](enum.TokenInstruction.html) /// instruction. pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult { Self::_process_initialize_multisig(accounts, m, true) } - /// Processes a [InitializeMultisig2](enum.TokenInstruction.html) + /// Processes a [`InitializeMultisig2`](enum.TokenInstruction.html) /// instruction. pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { Self::_process_initialize_multisig(accounts, m, false) } - /// Processes a [Transfer](enum.TokenInstruction.html) instruction. + /// Processes a [`Transfer`](enum.TokenInstruction.html) instruction. pub fn process_transfer( program_id: &Pubkey, accounts: &[AccountInfo], @@ -341,7 +342,7 @@ impl Processor { Ok(()) } - /// Processes an [Approve](enum.TokenInstruction.html) instruction. + /// Processes an [`Approve`](enum.TokenInstruction.html) instruction. pub fn process_approve( program_id: &Pubkey, accounts: &[AccountInfo], @@ -392,7 +393,7 @@ impl Processor { Ok(()) } - /// Processes an [Revoke](enum.TokenInstruction.html) instruction. + /// Processes an [`Revoke`](enum.TokenInstruction.html) instruction. pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let source_account_info = next_account_info(account_info_iter)?; @@ -420,7 +421,7 @@ impl Processor { Ok(()) } - /// Processes a [SetAuthority](enum.TokenInstruction.html) instruction. + /// Processes a [`SetAuthority`](enum.TokenInstruction.html) instruction. pub fn process_set_authority( program_id: &Pubkey, accounts: &[AccountInfo], @@ -518,7 +519,7 @@ impl Processor { Ok(()) } - /// Processes a [MintTo](enum.TokenInstruction.html) instruction. + /// Processes a [`MintTo`](enum.TokenInstruction.html) instruction. pub fn process_mint_to( program_id: &Pubkey, accounts: &[AccountInfo], @@ -583,7 +584,7 @@ impl Processor { Ok(()) } - /// Processes a [Burn](enum.TokenInstruction.html) instruction. + /// Processes a [`Burn`](enum.TokenInstruction.html) instruction. pub fn process_burn( program_id: &Pubkey, accounts: &[AccountInfo], @@ -668,7 +669,7 @@ impl Processor { Ok(()) } - /// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. + /// Processes a [`CloseAccount`](enum.TokenInstruction.html) instruction. pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let source_account_info = next_account_info(account_info_iter)?; @@ -709,8 +710,8 @@ impl Processor { Ok(()) } - /// Processes a [FreezeAccount](enum.TokenInstruction.html) or a - /// [ThawAccount](enum.TokenInstruction.html) instruction. + /// Processes a [`FreezeAccount`](enum.TokenInstruction.html) or a + /// [`ThawAccount`](enum.TokenInstruction.html) instruction. pub fn process_toggle_freeze_account( program_id: &Pubkey, accounts: &[AccountInfo], @@ -754,7 +755,7 @@ impl Processor { Ok(()) } - /// Processes a [SyncNative](enum.TokenInstruction.html) instruction + /// Processes a [`SyncNative`](enum.TokenInstruction.html) instruction pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); let native_account_info = next_account_info(account_info_iter)?; @@ -779,7 +780,8 @@ impl Processor { Ok(()) } - /// Processes a [GetAccountDataSize](enum.TokenInstruction.html) instruction + /// Processes a [`GetAccountDataSize`](enum.TokenInstruction.html) + /// instruction pub fn process_get_account_data_size( program_id: &Pubkey, accounts: &[AccountInfo], @@ -794,7 +796,7 @@ impl Processor { Ok(()) } - /// Processes an [InitializeImmutableOwner](enum.TokenInstruction.html) + /// Processes an [`InitializeImmutableOwner`](enum.TokenInstruction.html) /// instruction pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { let account_info_iter = &mut accounts.iter(); @@ -807,7 +809,8 @@ impl Processor { Ok(()) } - /// Processes an [AmountToUiAmount](enum.TokenInstruction.html) instruction + /// Processes an [`AmountToUiAmount`](enum.TokenInstruction.html) + /// instruction pub fn process_amount_to_ui_amount( program_id: &Pubkey, accounts: &[AccountInfo], @@ -825,7 +828,8 @@ impl Processor { Ok(()) } - /// Processes an [AmountToUiAmount](enum.TokenInstruction.html) instruction + /// Processes an [`AmountToUiAmount`](enum.TokenInstruction.html) + /// instruction pub fn process_ui_amount_to_amount( program_id: &Pubkey, accounts: &[AccountInfo], @@ -843,7 +847,7 @@ impl Processor { Ok(()) } - /// Processes an [Instruction](enum.Instruction.html). + /// Processes an [`Instruction`](enum.Instruction.html). pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { let instruction = TokenInstruction::unpack(input)?; diff --git a/program/src/state.rs b/program/src/state.rs index fe23fba..f7595e7 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -98,7 +98,7 @@ pub struct Account { pub delegate: COption, /// The account's state pub state: AccountState, - /// If is_native.is_some, this is a native token, and the value logs the + /// If `is_native.is_some`, this is a native token, and the value logs the /// rent-exempt reserve. An Account is required to be rent-exempt, so /// the value is used by the Processor to ensure that wrapped SOL /// accounts do not drop below this threshold. @@ -117,7 +117,7 @@ impl Account { pub fn is_native(&self) -> bool { self.is_native.is_some() } - /// Checks if a token Account's owner is the system_program or the + /// Checks if a token Account's owner is the `system_program` or the /// incinerator pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { solana_program::system_program::check_id(&self.owner) @@ -344,7 +344,7 @@ pub trait GenericTokenAccount { pub const ACCOUNT_INITIALIZED_INDEX: usize = 108; /// Check if the account data buffer represents an initialized account. -/// This is checking the `state` (AccountState) field of an Account object. +/// This is checking the `state` (`AccountState`) field of an Account object. pub fn is_initialized_account(account_data: &[u8]) -> bool { *account_data .get(ACCOUNT_INITIALIZED_INDEX) From 30521a195ba31b0bef54a07b41cbfd468df3aae6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:04:56 +0100 Subject: [PATCH 256/335] build(deps): bump bytemuck from 1.19.0 to 1.20.0 (#7507) Bumps [bytemuck](https://github.com/Lokathor/bytemuck) from 1.19.0 to 1.20.0. - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.19.0...v1.20.0) --- updated-dependencies: - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- program/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/Cargo.toml b/program/Cargo.toml index 93aea49..5a7f867 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -14,7 +14,7 @@ test-sbf = [] [dependencies] arrayref = "0.3.9" -bytemuck = "1.19.0" +bytemuck = "1.20.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" From f8bbbb7a5f216c4e39806d2a42c744fb1eb03299 Mon Sep 17 00:00:00 2001 From: Jon C Date: Wed, 18 Dec 2024 22:25:15 +0100 Subject: [PATCH 257/335] CI: Add program and all extra steps (#13) * CI: Add program and all extra steps #### Problem The token program now lives in its program-specific repo, but no part of it is being exercised by CI. #### Summary of changes Integrate the token program properly into CI. This includes: * add it to the Cargo workspace, and removing spl-token-client, since it's currently empty * run lint / format / test on the program * run spellcheck / audit / semver checks on the Rust packages * move rust scripts to `scripts/rust` and make them reusable * update to Solana 2.1 and proper rust toolchains * Move JS scripts around, build program too --- .github/workflows/main.yml | 134 +- Cargo.lock | 3630 ++++++++++------- Cargo.toml | 18 +- clients/rust/Cargo.toml | 9 +- clients/rust/src/lib.rs | 2 + package.json | 25 +- program/Cargo.toml | 8 +- program/Xargo.toml | 2 - program/inc/token.h | 687 ---- program/program-id.md | 1 - rust-toolchain.toml | 2 + rustfmt.toml | 15 +- scripts/client/test-rust.mjs | 18 - .../{client/format-js.mjs => js/format.mjs} | 0 scripts/{client/lint-js.mjs => js/lint.mjs} | 0 .../{client/publish-js.mjs => js/publish.mjs} | 0 scripts/{client/test-js.mjs => js/test.mjs} | 0 scripts/rust/audit.mjs | 31 + scripts/rust/build-sbf.mjs | 8 + .../format-rust.mjs => rust/format.mjs} | 12 +- .../{client/lint-rust.mjs => rust/lint.mjs} | 19 +- .../publish-rust.mjs => rust/publish.mjs} | 0 scripts/rust/test-sbf.mjs | 8 + scripts/solana.dic | 51 + scripts/spellcheck.toml | 6 + 25 files changed, 2519 insertions(+), 2167 deletions(-) delete mode 100644 program/Xargo.toml delete mode 100644 program/inc/token.h delete mode 100644 program/program-id.md create mode 100644 rust-toolchain.toml delete mode 100644 scripts/client/test-rust.mjs rename scripts/{client/format-js.mjs => js/format.mjs} (100%) rename scripts/{client/lint-js.mjs => js/lint.mjs} (100%) rename scripts/{client/publish-js.mjs => js/publish.mjs} (100%) rename scripts/{client/test-js.mjs => js/test.mjs} (100%) create mode 100644 scripts/rust/audit.mjs create mode 100644 scripts/rust/build-sbf.mjs rename scripts/{client/format-rust.mjs => rust/format.mjs} (72%) rename scripts/{client/lint-rust.mjs => rust/lint.mjs} (66%) rename scripts/{client/publish-rust.mjs => rust/publish.mjs} (100%) create mode 100644 scripts/rust/test-sbf.mjs create mode 100644 scripts/solana.dic create mode 100644 scripts/spellcheck.toml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ae467f2..46166f3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,6 +43,85 @@ jobs: - name: Lint Client Rust run: pnpm clients:rust:lint + format_and_lint_program: + name: Format & Lint Program + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + clippy: true + rustfmt: true + + - name: Format + run: pnpm programs:format + + - name: Lint + run: pnpm programs:lint + + audit_rust: + name: Audit Rust + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-audit + + - name: Install cargo-audit + uses: taiki-e/install-action@v2 + with: + tool: cargo-audit + + - name: Run cargo-audit + run: pnpm rust:audit + + semver_rust: + name: Check semver Rust + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-semver + + - name: Install cargo-audit + uses: taiki-e/install-action@v2 + with: + tool: cargo-semver-checks + + - name: Run semver checks + run: pnpm rust:semver + + spellcheck_rust: + name: Spellcheck Rust + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-spellcheck + + - name: Install cargo-spellcheck + uses: taiki-e/install-action@v2 + with: + tool: cargo-spellcheck + + - name: Run cargo-spellcheck + run: pnpm rust:spellcheck + generate_clients: name: Check Client Generation runs-on: ubuntu-latest @@ -63,10 +142,40 @@ jobs: git status --porcelain test -z "$(git status --porcelain)" + build_program: + name: Build Program + runs-on: ubuntu-latest + needs: format_and_lint_program + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-build-program + solana: true + + - name: Build + run: pnpm programs:build + + - name: Upload Program Builds + uses: actions/upload-artifact@v4 + with: + name: program-builds + path: ./target/deploy/*.so + if-no-files-found: error + + - name: Save Program Builds For Client Jobs + uses: actions/cache/save@v4 + with: + path: ./**/*.so + key: ${{ runner.os }}-builds-${{ github.sha }} + test_client_js: name: Test Client JS runs-on: ubuntu-latest - needs: format_and_lint_client_js + needs: [format_and_lint_client_js, build_program] steps: - name: Git Checkout uses: actions/checkout@v4 @@ -76,6 +185,12 @@ jobs: with: solana: true + - name: Restore Program Builds + uses: actions/cache/restore@v4 + with: + path: ./**/*.so + key: ${{ runner.os }}-builds-${{ github.sha }} + - name: Test Client JS run: pnpm clients:js:test @@ -96,3 +211,20 @@ jobs: - name: Test Client Rust run: pnpm clients:rust:test + + test_program: + name: Test Program + runs-on: ubuntu-latest + needs: format_and_lint_program + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-test-program + solana: true + + - name: Test + run: pnpm programs:test diff --git a/Cargo.lock b/Cargo.lock index c921c1b..e776334 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,32 +27,38 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aead" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ + "crypto-common", "generic-array", ] [[package]] name = "aes" -version = "0.7.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "opaque-debug", ] [[package]] name = "aes-gcm-siv" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" dependencies = [ "aead", "aes", @@ -64,14 +70,13 @@ dependencies = [ ] [[package]] -name = "ahash" -version = "0.7.8" +name = "agave-transaction-view" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +checksum = "e479181a1b6702e9d85e213757646c9011b525a3489101ed887b3fbae182659b" dependencies = [ - "getrandom 0.2.14", - "once_cell", - "version_check", + "solana-sdk", + "solana-svm-transaction", ] [[package]] @@ -96,12 +101,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -117,184 +116,6 @@ dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "anchor-attribute-access-control" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47fe28365b33e8334dd70ae2f34a43892363012fe239cf37d2ee91693575b1f8" -dependencies = [ - "anchor-syn", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-account" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c288d496168268d198d9b53ee9f4f9d260a55ba4df9877ea1d4486ad6109e0f" -dependencies = [ - "anchor-syn", - "bs58 0.5.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-constant" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b77b6948d0eeaaa129ce79eea5bbbb9937375a9241d909ca8fb9e006bb6e90" -dependencies = [ - "anchor-syn", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-error" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d20bb569c5a557c86101b944721d865e1fd0a4c67c381d31a44a84f07f84828" -dependencies = [ - "anchor-syn", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-event" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cebd8d0671a3a9dc3160c48598d652c34c77de6be4d44345b8b514323284d57" -dependencies = [ - "anchor-syn", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-program" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb2a5eb0860e661ab31aff7bb5e0288357b176380e985bade4ccb395981b42d" -dependencies = [ - "anchor-lang-idl", - "anchor-syn", - "anyhow", - "bs58 0.5.1", - "heck 0.3.3", - "proc-macro2", - "quote", - "serde_json", - "syn 1.0.109", -] - -[[package]] -name = "anchor-derive-accounts" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04368b5abef4266250ca8d1d12f4dff860242681e4ec22b885dcfe354fd35aa1" -dependencies = [ - "anchor-syn", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-derive-serde" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0bb0e0911ad4a70cab880cdd6287fe1e880a1a9d8e4e6defa8e9044b9796a6c" -dependencies = [ - "anchor-syn", - "borsh-derive-internal 0.10.3", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-derive-space" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef415ff156dc82e9ecb943189b0cb241b3a6bfc26a180234dc21bd3ef3ce0cb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-lang" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6620c9486d9d36a4389cab5e37dc34a42ed0bfaa62e6a75a2999ce98f8f2e373" -dependencies = [ - "anchor-attribute-access-control", - "anchor-attribute-account", - "anchor-attribute-constant", - "anchor-attribute-error", - "anchor-attribute-event", - "anchor-attribute-program", - "anchor-derive-accounts", - "anchor-derive-serde", - "anchor-derive-space", - "arrayref", - "base64 0.21.7", - "bincode", - "borsh 0.10.3", - "bytemuck", - "getrandom 0.2.14", - "solana-program", - "thiserror", -] - -[[package]] -name = "anchor-lang-idl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31cf97b4e6f7d6144a05e435660fcf757dbc3446d38d0e2b851d11ed13625bba" -dependencies = [ - "anchor-lang-idl-spec", - "anyhow", - "heck 0.3.3", - "serde", - "serde_json", - "sha2 0.10.8", -] - -[[package]] -name = "anchor-lang-idl-spec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdf143115440fe621bdac3a29a1f7472e09f6cd82b2aa569429a0c13f103838" -dependencies = [ - "anyhow", - "serde", -] - -[[package]] -name = "anchor-syn" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99daacb53b55cfd37ce14d6c9905929721137fd4c67bbab44a19802aecb622f" -dependencies = [ - "anyhow", - "bs58 0.5.1", - "heck 0.3.3", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2 0.10.8", - "syn 1.0.109", - "thiserror", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -310,20 +131,11 @@ dependencies = [ "libc", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "aquamarine" @@ -332,7 +144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" dependencies = [ "include_dir", - "itertools", + "itertools 0.10.5", "proc-macro-error", "proc-macro2", "quote", @@ -362,7 +174,7 @@ dependencies = [ "ark-std", "derivative", "hashbrown 0.13.2", - "itertools", + "itertools 0.10.5", "num-traits", "zeroize", ] @@ -379,8 +191,8 @@ dependencies = [ "ark-std", "derivative", "digest 0.10.7", - "itertools", - "num-bigint 0.4.4", + "itertools 0.10.5", + "num-bigint 0.4.6", "num-traits", "paste", "rustc_version", @@ -403,7 +215,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", @@ -432,7 +244,7 @@ dependencies = [ "ark-serialize-derive", "ark-std", "digest 0.10.7", - "num-bigint 0.4.4", + "num-bigint 0.4.6", ] [[package]] @@ -458,9 +270,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -486,7 +298,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -499,7 +311,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -526,7 +338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", "futures-core", ] @@ -545,23 +357,25 @@ dependencies = [ ] [[package]] -name = "async-mutex" -version = "1.4.0" +name = "async-lock" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener", + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -591,7 +405,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.2", "object", "rustc-demangle", ] @@ -616,15 +430,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" - -[[package]] -name = "base64ct" -version = "1.6.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bincode" @@ -635,6 +443,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "1.3.2" @@ -643,9 +466,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -661,9 +484,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.1" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -679,7 +502,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", "generic-array", ] @@ -692,22 +514,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "borsh" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" -dependencies = [ - "borsh-derive 0.9.3", - "hashbrown 0.11.2", -] - [[package]] name = "borsh" version = "0.10.3" @@ -720,35 +526,22 @@ dependencies = [ [[package]] name = "borsh" -version = "1.4.0" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6" +checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" dependencies = [ - "borsh-derive 1.4.0", + "borsh-derive 1.5.3", "cfg_aliases", ] -[[package]] -name = "borsh-derive" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" -dependencies = [ - "borsh-derive-internal 0.9.3", - "borsh-schema-derive-internal 0.9.3", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "borsh-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" dependencies = [ - "borsh-derive-internal 0.10.3", - "borsh-schema-derive-internal 0.10.3", + "borsh-derive-internal", + "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.109", @@ -756,27 +549,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.4.0" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5" +checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" dependencies = [ "once_cell", "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.60", - "syn_derive", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -790,17 +571,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "borsh-schema-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "borsh-schema-derive-internal" version = "0.10.3" @@ -833,12 +603,6 @@ dependencies = [ "alloc-stdlib", ] -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - [[package]] name = "bs58" version = "0.5.1" @@ -866,22 +630,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -892,9 +656,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "bzip2" @@ -924,20 +688,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" dependencies = [ "libc", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "cc" -version = "1.0.95" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -946,9 +716,20 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cfg_eval" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] [[package]] name = "chrono" @@ -976,73 +757,44 @@ dependencies = [ [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array", + "crypto-common", + "inout", ] [[package]] -name = "clap" -version = "2.34.0" +name = "combine" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim 0.8.0", - "textwrap 0.11.0", - "unicode-width", - "vec_map", + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", ] [[package]] -name = "clap" -version = "3.2.25" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex", - "indexmap 1.9.3", - "once_cell", - "strsim 0.10.0", - "termcolor", - "textwrap 0.16.1", + "bytes", + "memchr", ] [[package]] -name = "clap_lex" -version = "0.2.4" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "combine" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" -dependencies = [ - "ascii", - "byteorder", - "either", - "memchr", - "unreachable", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", + "crossbeam-utils", ] [[package]] @@ -1078,17 +830,11 @@ dependencies = [ "web-sys", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "core-foundation" @@ -1126,9 +872,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] @@ -1171,6 +917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] @@ -1186,27 +933,55 @@ dependencies = [ [[package]] name = "ctr" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", "serde", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "darling" version = "0.20.8" @@ -1227,8 +1002,8 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.60", + "strsim", + "syn 2.0.90", ] [[package]] @@ -1239,7 +1014,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -1262,15 +1037,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", -] - [[package]] name = "der-parser" version = "8.2.0" @@ -1280,7 +1046,7 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "rusticata-macros", ] @@ -1292,7 +1058,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", - "serde", ] [[package]] @@ -1312,18 +1077,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "dialoguer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" -dependencies = [ - "console", - "shell-words", - "tempfile", - "zeroize", -] - [[package]] name = "difflib" version = "0.4.0" @@ -1367,7 +1120,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -1390,7 +1143,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -1420,7 +1173,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.2.0", "ed25519", "rand 0.7.3", "serde", @@ -1490,7 +1243,7 @@ checksum = "c19cbb53d33b57ac4df1f0af6b92c38c107cded663c4aea9fae1189dcfc17cf5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -1499,11 +1252,11 @@ version = "3.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" dependencies = [ - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -1527,9 +1280,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1541,11 +1294,32 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "feature-probe" @@ -1553,6 +1327,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "filetime" version = "0.2.23" @@ -1565,14 +1345,29 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "five8_const" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" + [[package]] name = "flate2" -version = "1.0.29" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -1590,6 +1385,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1607,9 +1417,9 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1622,9 +1432,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1632,15 +1442,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1649,38 +1459,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1748,14 +1564,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] -name = "goblin" -version = "0.5.4" +name = "governor" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ - "log", - "plain", - "scroll", + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", ] [[package]] @@ -1770,7 +1595,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.6", + "indexmap", "slab", "tokio", "tokio-util 0.7.10", @@ -1786,31 +1611,13 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash 0.7.8", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] - [[package]] name = "hashbrown" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.11", + "ahash", ] [[package]] @@ -1820,13 +1627,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] -name = "heck" -version = "0.3.3" +name = "hashbrown" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -1849,12 +1653,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "histogram" version = "0.6.9" @@ -1964,7 +1762,7 @@ dependencies = [ "futures-util", "http", "hyper", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", ] @@ -1992,6 +1790,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -2000,12 +1916,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] @@ -2045,30 +1972,18 @@ dependencies = [ [[package]] name = "index_list" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70891286cb8e844fdfcf1178b47569699f9e20b5ecc4b45a6240a64771444638" - -[[package]] -name = "indexmap" -version = "1.9.3" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] +checksum = "fa38453685e5fe724fd23ff6c1a158c1e2ca21ce0c2718fa11e96e70e99fd4de" [[package]] name = "indexmap" -version = "2.2.6" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.5", - "serde", + "hashbrown 0.15.2", ] [[package]] @@ -2084,6 +1999,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -2108,6 +2032,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -2115,20 +2048,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] -name = "jobserver" -version = "0.1.31" +name = "jni" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" dependencies = [ - "libc", + "cesu8", + "combine 4.6.7", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", ] [[package]] -name = "js-sys" -version = "0.3.69" +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -2158,15 +2112,15 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libsecp256k1" @@ -2224,15 +2178,21 @@ checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" dependencies = [ "ark-bn254", "ark-ff", - "num-bigint 0.4.4", - "thiserror", + "num-bigint 0.4.6", + "thiserror 1.0.69", ] [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -2246,34 +2206,24 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "lru" -version = "0.7.8" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" -dependencies = [ - "hashbrown 0.12.3", -] +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lz4" -version = "1.24.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" dependencies = [ - "libc", "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.9.4" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" dependencies = [ "cc", "libc", @@ -2294,15 +2244,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.9.1" @@ -2330,6 +2271,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2345,6 +2296,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "0.8.11" @@ -2406,17 +2366,23 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "cfg-if", + "cfg_aliases", "libc", - "memoffset 0.7.1", - "pin-utils", + "memoffset", ] +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + [[package]] name = "nom" version = "7.1.3" @@ -2427,6 +2393,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -2460,11 +2432,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -2485,17 +2456,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "num-derive" version = "0.4.2" @@ -2504,7 +2464,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -2560,44 +2520,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" -dependencies = [ - "num_enum_derive 0.6.1", -] - -[[package]] -name = "num_enum" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" -dependencies = [ - "num_enum_derive 0.7.2", -] - -[[package]] -name = "num_enum_derive" -version = "0.6.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 2.0.60", + "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -2636,12 +2575,60 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.4.1+3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + [[package]] name = "opentelemetry" version = "0.17.0" @@ -2658,37 +2645,14 @@ dependencies = [ "percent-encoding", "pin-project", "rand 0.8.5", - "thiserror", -] - -[[package]] -name = "os_str_bytes" -version = "6.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" - -[[package]] -name = "ouroboros" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" -dependencies = [ - "aliasable", - "ouroboros_macro", + "thiserror 1.0.69", ] [[package]] -name = "ouroboros_macro" -version = "0.15.6" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" -dependencies = [ - "Inflector", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2719,15 +2683,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "pbkdf2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" -dependencies = [ - "crypto-mac", -] - [[package]] name = "pbkdf2" version = "0.11.0" @@ -2778,7 +2733,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -2793,34 +2748,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs8" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" -dependencies = [ - "der", - "spki", - "zeroize", -] - [[package]] name = "pkg-config" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "polyval" -version = "0.5.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", @@ -2854,7 +2792,7 @@ checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", "float-cmp", - "itertools", + "itertools 0.10.5", "normalize-line-endings", "predicates-core", "regex", @@ -2885,23 +2823,13 @@ dependencies = [ "toml", ] -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - [[package]] name = "proc-macro-crate" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] @@ -2930,13 +2858,33 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + [[package]] name = "qstring" version = "0.7.2" @@ -2954,55 +2902,81 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", +] + +[[package]] +name = "quanta" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773ce68d0bb9bc7ef20be3536ffe94e223e1f365bd374108b2659fac0c65cfe6" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quinn" -version = "0.10.2" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash", - "rustls", - "thiserror", + "rustls 0.23.20", + "socket2", + "thiserror 2.0.7", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.10.6" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom 0.2.14", "rand 0.8.5", - "ring 0.16.20", + "ring", "rustc-hash", - "rustls", - "rustls-native-certs", + "rustls 0.23.20", + "rustls-pki-types", + "rustls-platform-verifier", "slab", - "thiserror", + "thiserror 2.0.7", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.4.1" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" dependencies = [ - "bytes", + "cfg_aliases", "libc", + "once_cell", "socket2", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3085,6 +3059,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "rand_xoshiro" version = "0.6.0" @@ -3094,6 +3077,15 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "raw-cpuid" +version = "11.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "rayon" version = "1.10.0" @@ -3114,18 +3106,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "rcgen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" -dependencies = [ - "pem", - "ring 0.16.20", - "time", - "yasna", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -3141,14 +3121,14 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -3158,9 +3138,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3169,9 +3149,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -3194,11 +3174,12 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -3217,18 +3198,18 @@ dependencies = [ ] [[package]] -name = "ring" -version = "0.16.20" +name = "reqwest-middleware" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "task-local-extensions", + "thiserror 1.0.69", ] [[package]] @@ -3241,32 +3222,11 @@ dependencies = [ "cfg-if", "getrandom 0.2.14", "libc", - "spin 0.9.8", - "untrusted 0.9.0", + "spin", + "untrusted", "windows-sys 0.52.0", ] -[[package]] -name = "rpassword" -version = "7.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" -dependencies = [ - "libc", - "rtoolbox", - "windows-sys 0.48.0", -] - -[[package]] -name = "rtoolbox" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -3275,9 +3235,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc_version" @@ -3299,11 +3259,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -3317,19 +3277,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.17.8", - "rustls-webpki", + "ring", + "rustls-webpki 0.101.7", "sct", ] [[package]] -name = "rustls-native-certs" -version = "0.6.3" +name = "rustls" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 2.2.0", + "rustls-pki-types", "schannel", "security-framework", ] @@ -3343,14 +3318,70 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c7dc240fec5517e6c4eab3310438636cfe6391dfc345ba013109909a90d136" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.20", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.8", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -3359,6 +3390,18 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.17" @@ -3374,6 +3417,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scc" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b13f8ea6177672c49d12ed964cca44836f59621981b04a3e26b87e675181de" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" version = "0.1.23" @@ -3394,20 +3446,6 @@ name = "scroll" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] [[package]] name = "sct" @@ -3415,10 +3453,16 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring", + "untrusted", ] +[[package]] +name = "sdd" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9" + [[package]] name = "security-framework" version = "2.10.0" @@ -3429,6 +3473,7 @@ dependencies = [ "core-foundation", "core-foundation-sys", "libc", + "num-bigint 0.4.6", "security-framework-sys", ] @@ -3444,9 +3489,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "seqlock" @@ -3459,40 +3504,41 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.199" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -3511,54 +3557,50 @@ dependencies = [ [[package]] name = "serde_with" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" -dependencies = [ - "serde", - "serde_with_macros 2.3.3", -] - -[[package]] -name = "serde_with" -version = "3.8.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ - "base64 0.22.0", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.2.6", "serde", "serde_derive", - "serde_json", - "serde_with_macros 3.8.1", - "time", + "serde_with_macros", ] [[package]] name = "serde_with_macros" -version = "2.3.3" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] -name = "serde_with_macros" -version = "3.8.1" +name = "serial_test" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ - "darling", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -3596,18 +3638,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] - [[package]] name = "sha3" version = "0.10.8" @@ -3628,10 +3658,10 @@ dependencies = [ ] [[package]] -name = "shell-words" -version = "1.1.0" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" @@ -3689,192 +3719,275 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "solana-account" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b4e43476f7e13b6a8f571008cc6aff6ff0cae6e9c71ca96e6feb787e3409fd" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-program", +] + [[package]] name = "solana-account-decoder" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142161f13c328e7807fe98fb8f6eaaa5045a8eaf4492414aa81254870c4fc8a0" +checksum = "c195abdb9665bb390eda3972b750d04f87a5b023cfde6674a61b03452de15585" dependencies = [ "Inflector", - "base64 0.21.7", + "base64 0.22.1", "bincode", - "bs58 0.4.0", + "bs58", "bv", "lazy_static", "serde", "serde_derive", "serde_json", + "solana-account-decoder-client-types", "solana-config-program", "solana-sdk", - "spl-token", + "spl-token 6.0.0", "spl-token-2022", "spl-token-group-interface", "spl-token-metadata-interface", - "thiserror", + "thiserror 1.0.69", + "zstd", +] + +[[package]] +name = "solana-account-decoder-client-types" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b743d836d14dea475cc0a82a3f31316563888af97d06f5575a90f8ceb859f2" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-pubkey", "zstd", ] +[[package]] +name = "solana-account-info" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42051fa2def3a2d9123f0e33b62a983b25c13d153a30e707b14d3c3b79a91592" +dependencies = [ + "bincode", + "serde", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", +] + [[package]] name = "solana-accounts-db" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e8b4b15e353d5f0e0ddd77966c6f01b296bd83569af455da5fd9329356ff642" +checksum = "06cd13cf8d4db51dd1bb94c6b6a7ca5a1f4f26ddd1c5f708d9631838790d1931" dependencies = [ - "arrayref", + "ahash", "bincode", "blake3", "bv", "bytemuck", - "byteorder", + "bytemuck_derive", "bzip2", "crossbeam-channel", "dashmap", - "flate2", - "fnv", - "im", "index_list", - "itertools", + "indexmap", + "itertools 0.12.1", "lazy_static", "log", "lz4", "memmap2", "modular-bitfield", - "num-derive 0.4.2", - "num-traits", "num_cpus", - "num_enum 0.7.2", - "ouroboros", - "percentage", - "qualifier_attr", + "num_enum", "rand 0.8.5", "rayon", - "regex", - "rustc_version", "seqlock", "serde", "serde_derive", "smallvec", "solana-bucket-map", - "solana-config-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-inline-spl", + "solana-lattice-hash", "solana-measure", "solana-metrics", "solana-nohash-hasher", - "solana-program-runtime", "solana-rayon-threadlimit", "solana-sdk", - "solana-stake-program", - "solana-system-program", - "solana-vote-program", + "solana-svm-transaction", "static_assertions", - "strum", - "strum_macros", "tar", "tempfile", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "solana-address-lookup-table-program" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eef9fc8aa3ff804dbf17766ab2d2fe38561adc8b521705faa782c18a108d8" +checksum = "f1ecf05f94decc544055d61a2071a4dddd590d29c945061cf9abeac662020ec7" dependencies = [ "bincode", "bytemuck", "log", - "num-derive 0.4.2", + "num-derive", "num-traits", - "rustc_version", - "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-feature-set", + "solana-log-collector", "solana-program", "solana-program-runtime", "solana-sdk", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10dad9cf8527bbf74d3668505f563bd362e2e14d0fc77338d20973e881bbad0b" +dependencies = [ + "parking_lot", ] [[package]] name = "solana-banks-client" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13a4cbe27e78987b706caf90cbd16da9da3955c09a660b8107a96c2cb32f1124" +checksum = "cad332be8ddaadb313b811853c21ff373a821c5e7a52a3e0757aabef4570b9d1" dependencies = [ - "borsh 1.4.0", + "borsh 1.5.3", "futures", "solana-banks-interface", "solana-program", "solana-sdk", "tarpc", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-serde", ] [[package]] name = "solana-banks-interface" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "741279a09bf5ea1a3d17e591db7b189e163722e5c46423308c6a6165bea5e74d" +checksum = "52f1ba996f5b9214865dfe561d113f2cec114910ab82097035918aab228c0ede" dependencies = [ "serde", + "serde_derive", "solana-sdk", "tarpc", ] [[package]] name = "solana-banks-server" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66768544951feb91c3470e255d4613295b5cc5a58a9cc6a4207ab9a0178cfe9" +checksum = "35e3c78eb17b9af871f34c213115cfc1b0fe5125686a0a21171d62ea7ac44b96" dependencies = [ "bincode", "crossbeam-channel", "futures", - "solana-accounts-db", "solana-banks-interface", "solana-client", + "solana-feature-set", "solana-runtime", "solana-sdk", "solana-send-transaction-service", + "solana-svm", "tarpc", "tokio", "tokio-serde", ] +[[package]] +name = "solana-bincode" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e3b178d3783809a2480c542cd7c57c06e1bab2c0f21562fcb8cd13eabd0138e" +dependencies = [ + "bincode", + "serde", + "solana-instruction", +] + +[[package]] +name = "solana-bn254" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8f9c849dac8e6ef87c3c8035886df648ef5ec4c6d9d45b96fc045477e23a9b0" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "bytemuck", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-borsh" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870197ea4929500d8e6f624c3eb578912b5063bbd5c8bfbe87396cd5b4257465" +dependencies = [ + "borsh 0.10.3", + "borsh 1.5.3", +] + [[package]] name = "solana-bpf-loader-program" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e9dd5e42193260cca0794bf4ab9e248f44b3d9710041f241b130d26ed682bc" +checksum = "6a529f5e85392e5c628f188a4b5f40e90d25bf303380b04c4f6272412a0501c0" dependencies = [ "bincode", "byteorder", "libsecp256k1", "log", "scopeguard", + "solana-bn254", + "solana-compute-budget", + "solana-curve25519", + "solana-feature-set", + "solana-log-collector", "solana-measure", + "solana-poseidon", + "solana-program-memory", "solana-program-runtime", "solana-sdk", - "solana-zk-token-sdk", + "solana-timings", + "solana-type-overrides", "solana_rbpf", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "solana-bucket-map" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7b34296d69867253671a71a2231b8d5b4a810bd7a5c1c603e7b542832d5980" +checksum = "aeecd14db2155d6576ad5694bbc27e201b0a08c018e5e15c6d5be4893b503a14" dependencies = [ "bv", "bytemuck", + "bytemuck_derive", "log", "memmap2", "modular-bitfield", - "num_enum 0.7.2", + "num_enum", "rand 0.8.5", "solana-measure", "solana-sdk", @@ -3882,41 +3995,43 @@ dependencies = [ ] [[package]] -name = "solana-clap-utils" -version = "1.18.12" +name = "solana-builtins-default-costs" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e9f61034a61db538a41700b6df0b4b9f0392038adaf780150481923ff94356" +checksum = "3327ae9cd1e31aed84f2c34ed17b7a940d2ca1fcc1ab414f551833a51d6cbf3a" dependencies = [ - "chrono", - "clap 2.34.0", - "rpassword", - "solana-remote-wallet", + "ahash", + "lazy_static", + "log", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-config-program", + "solana-loader-v4-program", "solana-sdk", - "thiserror", - "tiny-bip39", - "uriparse", - "url", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", ] [[package]] name = "solana-client" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f2bd5a986d7cac1b4ffb4344413b70b6f21fd7ffa92a985911756b4ac7682a" +checksum = "1502052be06ff6bfc86363955c2bf06e5f9640689fdb5900e5aa7d5b22633a9d" dependencies = [ "async-trait", "bincode", "dashmap", "futures", "futures-util", - "indexmap 2.2.6", + "indexmap", "indicatif", "log", "quinn", "rayon", "solana-connection-cache", "solana-measure", - "solana-metrics", "solana-pubsub-client", "solana-quic-client", "solana-rpc-client", @@ -3927,15 +4042,36 @@ dependencies = [ "solana-thin-client", "solana-tpu-client", "solana-udp-client", - "thiserror", + "thiserror 1.0.69", "tokio", ] +[[package]] +name = "solana-clock" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b26a68f89972fddb370ba33a49340bd3419da529893d9ee851211588aee811fa" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-compute-budget" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3366dd8be1d12ea197392cdc261ea1630d156b5685647ed7769959ef473f8aae" +dependencies = [ + "solana-sdk", +] + [[package]] name = "solana-compute-budget-program" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca100b2bdd7e455f5f0b9791bc204dacd684a0373ad1032697dbad43f34e527f" +checksum = "700e90029b4aa3907bef8f5964451a5495cfc25a89374d0e94b7887b780ca587" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -3943,140 +4079,288 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970d28779e92a11e32a89ee453edc7d89394d3a68d8c4b75ef0ffb833944c588" +checksum = "01b94dd5229242839bf71572d903a38f2ea40db5ad408eca57015bcaaf2a7607" dependencies = [ "bincode", "chrono", "serde", "serde_derive", + "solana-log-collector", "solana-program-runtime", "solana-sdk", + "solana-short-vec", ] [[package]] name = "solana-connection-cache" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7d0022ded19dca32ced5528c6a050596877fc8b9a89322d876960a89466e1b" +checksum = "1445dd6a6d47b7a025af9f9c44ecb333716a5a6859f77f8da210d86bb89a7627" dependencies = [ "async-trait", "bincode", "crossbeam-channel", "futures-util", - "indexmap 2.2.6", + "indexmap", "log", "rand 0.8.5", "rayon", - "rcgen", "solana-measure", "solana-metrics", "solana-sdk", - "thiserror", + "thiserror 1.0.69", "tokio", ] [[package]] name = "solana-cost-model" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd3c63699df1680535daee8e486bd496e2ec849c427de4b6a42d4f1b27430949" +checksum = "21f05cbc354339b05f7ceb9e3ee8ac95ef1abdf260383d57b93f6a06cd06805e" dependencies = [ + "ahash", "lazy_static", "log", - "rustc_version", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-compute-budget-program", - "solana-config-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-loader-v4-program", + "solana-builtins-default-costs", + "solana-compute-budget", + "solana-feature-set", "solana-metrics", - "solana-program-runtime", + "solana-runtime-transaction", "solana-sdk", - "solana-stake-program", - "solana-system-program", + "solana-svm-transaction", "solana-vote-program", ] [[package]] -name = "solana-frozen-abi" -version = "1.18.12" +name = "solana-cpi" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a0b24cc4d0ebd5fd45d6bd47bed3790f8a75ade67af8ff24a3d719a8bc93bc" +checksum = "9e3b62e1ca838f92b90c25ab68c297272cee8e2256dad18806a219b05cfcd247" dependencies = [ - "block-buffer 0.10.4", - "bs58 0.4.0", - "bv", - "either", - "generic-array", - "im", - "lazy_static", - "log", - "memmap2", - "rustc_version", - "serde", - "serde_bytes", - "serde_derive", - "sha2 0.10.8", - "solana-frozen-abi-macro", - "subtle", - "thiserror", + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", ] [[package]] -name = "solana-frozen-abi-macro" -version = "1.18.12" +name = "solana-curve25519" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51600f4066d3663ab2981fd24e77a8c2e65f5d20ea71b550b853ca9ae40eee7f" +checksum = "d2ce85c03e05856b4094891fbaedf9ea9b0334b19d8fba72bd4b106442b46e12" dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.60", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "solana-program", + "thiserror 1.0.69", ] [[package]] -name = "solana-loader-v4-program" -version = "1.18.12" +name = "solana-decode-error" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c566ebf0da216efc70054bf2d6d06c16fe44b63402c6f3bb04f6a88d8571d9b" +checksum = "1323dbdb7c8ca717bcd7987a3f45619b5b6517dc3ee22a21342122a5516125c3" dependencies = [ - "log", - "solana-measure", - "solana-program-runtime", - "solana-sdk", - "solana_rbpf", + "num-traits", ] [[package]] -name = "solana-logger" -version = "1.18.12" +name = "solana-define-syscall" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79ef26804612173c95be8da84df3128d648173cf1f746de8f183ec8dbedd92" +checksum = "a23cf0144176f94019a27ce46372661f67007232eea16cae96cb985fc25131d5" + +[[package]] +name = "solana-derivation-path" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ccae348499724f35dd03f395b415c54ab3929799c90df0d33e9878947e0987" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60dde3613fcd1af91c2033e67ffe8c8d2bcd58085c53c842fa7903fa839ad38" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-feature-set" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c225a8a8be02a514d4180e6a7c6ff68e193c8e722ac14cde565fe68b671a4a" dependencies = [ - "env_logger", "lazy_static", + "solana-clock", + "solana-epoch-schedule", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-fee" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b87b940cad820c4ae7af3fed8598e35c042adade5b91dee51218015bb5f906" +dependencies = [ + "solana-sdk", + "solana-svm-transaction", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c706f3d151d0abc197ca2fcecf877ace03d613be6fae766de12f5fb41c96b04" +dependencies = [ "log", + "serde", + "serde_derive", ] [[package]] -name = "solana-measure" -version = "1.18.12" +name = "solana-hash" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300f716a5f1c2f4b562fb008a0cc7d7c0d889cff802a7f8177fdf28772ae1ed9" +checksum = "a86aabbd7ebf807689a0355f053d6dc31d2131c2d83613011a374a18cc5d61b7" +dependencies = [ + "borsh 1.5.3", + "bs58", + "bytemuck", + "bytemuck_derive", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-inflation" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6954cd9fb4cd351e9e01d3fda020936f7cb44eb9efab3baecc3a5de1c9de8c1a" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-inline-spl" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f116f35b0b8ec99abf0e0cda7064eb3dfb6d16e8bc8767c116f91c256db9b859" +dependencies = [ + "bytemuck", + "solana-pubkey", +] + +[[package]] +name = "solana-instruction" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94ed5710c998efd09ffb596cf5e7266c11cd56e3a136c8a1f940e8525fd5be6e" +dependencies = [ + "bincode", + "borsh 1.5.3", + "getrandom 0.2.14", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd5647af0980c796c942e33f1f7dbffca29b7747630b720e6975abb1d7c531f6" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-lattice-hash" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cb58f78f4c7424344cca3fffa3210f5c10bae9b57639a5bc43b2111e8551160" +dependencies = [ + "base64 0.22.1", + "blake3", + "bs58", + "bytemuck", +] + +[[package]] +name = "solana-loader-v4-program" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d281df3057ee55a83081b399947fcbf50b5a1726c64b1d86bae291fe16db08" dependencies = [ "log", + "solana-bpf-loader-program", + "solana-compute-budget", + "solana-log-collector", + "solana-measure", + "solana-program-runtime", "solana-sdk", + "solana-type-overrides", + "solana_rbpf", +] + +[[package]] +name = "solana-log-collector" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636132217fc00b32a72a3fff2dfdda5a377291edc788d3286a3fbf73caaf89cf" +dependencies = [ + "log", ] +[[package]] +name = "solana-logger" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037e89416c5f3e160841a3717241f86e5a3e1b3edf4d946e976b4960c11e1073" +dependencies = [ + "env_logger", + "lazy_static", + "log", +] + +[[package]] +name = "solana-measure" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc2470b663cde7fcd3dc644fdcb19181cf5d87ece8cab270e182ff33b48b357" + [[package]] name = "solana-metrics" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf1705d52e4f123856725e1b3842cd4928b954ff62391a95af142a5adc58ac6" +checksum = "dc3248d11553718544485736382dd9a8b619f42f39fba41b9211638d35414bbc" dependencies = [ "crossbeam-channel", "gethostname", @@ -4084,17 +4368,31 @@ dependencies = [ "log", "reqwest", "solana-sdk", - "thiserror", + "thiserror 1.0.69", ] +[[package]] +name = "solana-msg" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d6a46fcbbaa38193b5b6aeec531395da8dac8dcd183ac6d80d94e6513fc4ad8" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-native-token" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa3c5006bbea99b810ad8fc6ae168fc83891b607a13a9aa6be39db71a700f87" + [[package]] name = "solana-net-utils" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f2634fd50743e2ca075e663e07b0bd5c2f94db0ac320ce5bc2022e0002d82d" +checksum = "521d93b4023bfce59bff12f7821ab6803ddfdf8d6ead19e8bbdeaee84a609a18" dependencies = [ "bincode", - "clap 3.2.25", "crossbeam-channel", "log", "nix", @@ -4102,9 +4400,7 @@ dependencies = [ "serde", "serde_derive", "socket2", - "solana-logger", "solana-sdk", - "solana-version", "tokio", "url", ] @@ -4115,17 +4411,31 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" +[[package]] +name = "solana-packet" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05fd58e2633824294a4eb1159e3f2cd9fed8d8c4d25fb4e3388f872c314e5ffd" +dependencies = [ + "bincode", + "bitflags 2.6.0", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + [[package]] name = "solana-perf" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0264d7093d44c239d9eb41beb6877b7b1eea5ad8809c93c1d9ab0c840ba390" +checksum = "adbb524303dd629a59dc08352da0d232f54172c5454948749966b370eac3ea2a" dependencies = [ - "ahash 0.8.11", + "ahash", "bincode", "bv", "caps", - "curve25519-dalek", + "curve25519-dalek 4.1.3", "dlopen2", "fnv", "lazy_static", @@ -4134,108 +4444,201 @@ dependencies = [ "nix", "rand 0.8.5", "rayon", - "rustc_version", "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", "solana-metrics", "solana-rayon-threadlimit", "solana-sdk", + "solana-short-vec", "solana-vote-program", ] [[package]] -name = "solana-program" -version = "1.18.12" +name = "solana-poseidon" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5513a02d622ba89e76baf4b49d25ae20c2c2c623fced12b0d6dd7b8f23e006" +checksum = "789063a1bc183d95d5a62787c7d85fe1d0dc1f08f2282a7124dc5e913221ae3b" dependencies = [ "ark-bn254", - "ark-ec", - "ark-ff", - "ark-serialize", - "base64 0.21.7", + "light-poseidon", + "solana-define-syscall", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-precompile-error" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e289d47a9c60b9636d86458e050eca1a74f7c932abeee3bca2a0c256b8c9814e" +dependencies = [ + "num-traits", + "solana-decode-error", +] + +[[package]] +name = "solana-program" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afc847b91b77c48113a55f7f492cc7e982e1778c6b954a05feb499f9b8c3cc4" +dependencies = [ + "base64 0.22.1", "bincode", - "bitflags 2.5.0", + "bitflags 2.6.0", "blake3", "borsh 0.10.3", - "borsh 0.9.3", - "borsh 1.4.0", - "bs58 0.4.0", + "borsh 1.5.3", + "bs58", "bv", "bytemuck", - "cc", + "bytemuck_derive", "console_error_panic_hook", "console_log", - "curve25519-dalek", + "curve25519-dalek 4.1.3", + "five8_const", "getrandom 0.2.14", - "itertools", "js-sys", "lazy_static", - "libc", - "libsecp256k1", - "light-poseidon", "log", - "memoffset 0.9.1", - "num-bigint 0.4.4", - "num-derive 0.4.2", + "memoffset", + "num-bigint 0.4.6", + "num-derive", "num-traits", "parking_lot", "rand 0.8.5", - "rustc_version", - "rustversion", "serde", "serde_bytes", "serde_derive", - "serde_json", "sha2 0.10.8", - "sha3 0.10.8", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "sha3", + "solana-account-info", + "solana-atomic-u64", + "solana-bincode", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-last-restart-slot", + "solana-msg", + "solana-native-token", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sanitize", "solana-sdk-macro", - "thiserror", - "tiny-bip39", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-sysvar-id", + "solana-transaction-error", + "thiserror 1.0.69", "wasm-bindgen", - "zeroize", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "988a49fb8231e95861d11b40931f49e06f0dea5a29241acf7cbca644c52abd6b" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2473773ee9cebf6ba3d7d1fe911938bc2a3a694e85bea33fd7a99d397cde1202" +dependencies = [ + "borsh 1.5.3", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d9e6ca90bbc3020b7b37091c05049f5de48e397545093ec303dc6eff3d4720c" +dependencies = [ + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2334c5f9adcc25c6390fbf87ac127adbfbd8943465726e5f389159677ceba2" + +[[package]] +name = "solana-program-pack" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305475eef9404539cce0c561ab9997b875cc5509f7c553859cd059fdf93b0ab2" +dependencies = [ + "solana-program-error", ] [[package]] name = "solana-program-runtime" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64dc9f666a8e4f93166ce58eea9dfbf275e5cad461b2f1bbfa06538718dc3212" +checksum = "05abf5a66475f23769700597129cce9f76cfaacb45babf83ffec3157da8c7ce4" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "bincode", - "eager", "enum-iterator", - "itertools", + "itertools 0.12.1", "libc", "log", - "num-derive 0.4.2", + "num-derive", "num-traits", "percentage", "rand 0.8.5", - "rustc_version", "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-compute-budget", + "solana-feature-set", + "solana-log-collector", "solana-measure", "solana-metrics", "solana-sdk", + "solana-timings", + "solana-type-overrides", + "solana-vote", "solana_rbpf", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "solana-program-test" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2760112327ffce892f6a21030f7c9e4b6da3ded8c8eadf1dbfffcb5a754c61db" +checksum = "2f12ddc1b98a4af13a4c0ff9b67ae5a4a58c79fcb7602501fcb6679d1e9d783b" dependencies = [ "assert_matches", "async-trait", - "base64 0.21.7", + "base64 0.22.1", "bincode", "chrono-humanize", "crossbeam-channel", @@ -4246,22 +4649,55 @@ dependencies = [ "solana-banks-interface", "solana-banks-server", "solana-bpf-loader-program", + "solana-compute-budget", + "solana-feature-set", + "solana-inline-spl", + "solana-instruction", + "solana-log-collector", "solana-logger", "solana-program-runtime", "solana-runtime", "solana-sdk", + "solana-svm", + "solana-timings", "solana-vote-program", "solana_rbpf", - "test-case", - "thiserror", + "thiserror 1.0.69", "tokio", ] +[[package]] +name = "solana-pubkey" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a954fba3af498201179981818b0ed61f95c32b4a3db5ea9cc042c971c84cdeae" +dependencies = [ + "borsh 0.10.3", + "borsh 1.5.3", + "bs58", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.14", + "js-sys", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + [[package]] name = "solana-pubsub-client" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdcbdad685b87475a91909fdb442d2edfabc2870110580c7f0cf7eb7883f97" +checksum = "28f6f2c554cec02f87eca3e2461e1923db157d2d615e919fc2b93807465cbe6a" dependencies = [ "crossbeam-channel", "futures-util", @@ -4274,7 +4710,7 @@ dependencies = [ "solana-account-decoder", "solana-rpc-client-api", "solana-sdk", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tokio-tungstenite", @@ -4284,20 +4720,19 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056e909037b05097d2ff0181cb7e3d26876d8dff6d50701463a61e990cf84afd" +checksum = "4c707a5c4aba604c06c0eeced102355229a7696ed4dc6a26c71bba5d74d86fc5" dependencies = [ - "async-mutex", + "async-lock", "async-trait", "futures", - "itertools", + "itertools 0.12.1", "lazy_static", "log", "quinn", "quinn-proto", - "rcgen", - "rustls", + "rustls 0.23.20", "solana-connection-cache", "solana-measure", "solana-metrics", @@ -4305,60 +4740,54 @@ dependencies = [ "solana-rpc-client-api", "solana-sdk", "solana-streamer", - "thiserror", + "thiserror 1.0.69", "tokio", ] [[package]] name = "solana-rayon-threadlimit" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93a5e1ef891dca2cca907f7196b6a5d3b80af4183f2be0f981906b16711ff5d" +checksum = "6eeb2db0e5055cc45bbb9b6f8e4bc879b49dadf5734397a749c4b7da9193e71e" dependencies = [ "lazy_static", "num_cpus", ] [[package]] -name = "solana-remote-wallet" -version = "1.18.12" +name = "solana-rent" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c06eaf47d9a98ba22e890e68868f5d48c91e01268c541a53b5960288b617d6" +checksum = "4ebcc59bff8b3c773214545d038b718a3e2e63c920b8172f85725463029f7f00" dependencies = [ - "console", - "dialoguer", - "log", - "num-derive 0.4.2", - "num-traits", - "parking_lot", - "qstring", - "semver", - "solana-sdk", - "thiserror", - "uriparse", + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", ] [[package]] name = "solana-rpc-client" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1d4b6f1f4e3dab7509401e85edc1c1ac208c61819de90178e01cf162c9c051" +checksum = "c85883f214cff98a97432646ace94eea3cfe309b068841c0feae93d0a1e7b238" dependencies = [ "async-trait", - "base64 0.21.7", + "base64 0.22.1", "bincode", - "bs58 0.4.0", + "bs58", "indicatif", "log", "reqwest", + "reqwest-middleware", "semver", "serde", "serde_derive", "serde_json", - "solana-account-decoder", + "solana-account-decoder-client-types", "solana-rpc-client-api", "solana-sdk", - "solana-transaction-status", + "solana-transaction-status-client-types", "solana-version", "solana-vote-program", "tokio", @@ -4366,48 +4795,49 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31feddef24d3e0aab189571adea7f109639ef6179fcd3cd34ffc8c73d3409f1" +checksum = "791168d04387734755d3a7e81f5228cb305041c09bf4fbfc0823c8380acdf3e7" dependencies = [ - "base64 0.21.7", - "bs58 0.4.0", + "anyhow", + "base64 0.22.1", + "bs58", "jsonrpc-core", "reqwest", + "reqwest-middleware", "semver", "serde", "serde_derive", "serde_json", - "solana-account-decoder", + "solana-account-decoder-client-types", + "solana-inline-spl", "solana-sdk", - "solana-transaction-status", + "solana-transaction-status-client-types", "solana-version", - "spl-token-2022", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1837728262063723c659e4b8c0acf0baa99cd38cb333511456465d2c9e654474" +checksum = "46e515480bef7a3476cee636a69aa237e2e8ba73f82ba95d6e307397144ce4fc" dependencies = [ - "clap 2.34.0", - "solana-clap-utils", "solana-rpc-client", "solana-sdk", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "solana-runtime" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3480088ad0ffb701ada496f19754b4ff737e516c6b5f1231508e50ae2e0ea3" +checksum = "297794ae50b36180a7c769c864b83cbfb91ea438019ea15bcff66e21f6b7e048" dependencies = [ + "ahash", "aquamarine", "arrayref", - "base64 0.21.7", + "base64 0.22.1", "bincode", "blake3", "bv", @@ -4421,49 +4851,60 @@ dependencies = [ "fnv", "im", "index_list", - "itertools", + "itertools 0.12.1", "lazy_static", + "libc", "log", - "lru", "lz4", "memmap2", "mockall", "modular-bitfield", - "num-derive 0.4.2", + "num-derive", "num-traits", "num_cpus", - "num_enum 0.7.2", - "ouroboros", + "num_enum", "percentage", "qualifier_attr", "rand 0.8.5", "rayon", "regex", - "rustc_version", "serde", "serde_derive", "serde_json", + "serde_with", "solana-accounts-db", "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-bucket-map", + "solana-compute-budget", "solana-compute-budget-program", "solana-config-program", "solana-cost-model", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-feature-set", + "solana-fee", + "solana-inline-spl", + "solana-lattice-hash", "solana-loader-v4-program", "solana-measure", "solana-metrics", "solana-perf", + "solana-program", "solana-program-runtime", "solana-rayon-threadlimit", + "solana-runtime-transaction", "solana-sdk", "solana-stake-program", + "solana-svm", + "solana-svm-rent-collector", + "solana-svm-transaction", "solana-system-program", + "solana-timings", + "solana-transaction-status", "solana-version", "solana-vote", "solana-vote-program", + "solana-zk-elgamal-proof-program", + "solana-zk-sdk", "solana-zk-token-proof-program", "solana-zk-token-sdk", "static_assertions", @@ -4472,76 +4913,132 @@ dependencies = [ "symlink", "tar", "tempfile", - "thiserror", + "thiserror 1.0.69", "zstd", ] +[[package]] +name = "solana-runtime-transaction" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df2638adfc8975cb111bc2ab3ee2cb04572ecbc96d1b414f1c9838729dc0c54" +dependencies = [ + "agave-transaction-view", + "log", + "solana-builtins-default-costs", + "solana-compute-budget", + "solana-pubkey", + "solana-sdk", + "solana-svm-transaction", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-sanitize" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05ecd7ec442abf0561cbf06984484d6368e71a4882213bfa68b658b0f8d6a0e" + [[package]] name = "solana-sdk" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f50cac89269a01235f6b421bc580132191f4df388f4265513e78fd00cf864dd" +checksum = "216fa7d6ef4d741ec21e0054e78d86c5da0c2033f377b03de5eb65d264d8df13" dependencies = [ - "assert_matches", - "base64 0.21.7", "bincode", - "bitflags 2.5.0", - "borsh 1.4.0", - "bs58 0.4.0", + "bitflags 2.6.0", + "borsh 1.5.3", + "bs58", "bytemuck", + "bytemuck_derive", "byteorder", "chrono", - "derivation-path", "digest 0.10.7", "ed25519-dalek", "ed25519-dalek-bip32", - "generic-array", + "getrandom 0.1.16", "hmac 0.12.1", - "itertools", + "itertools 0.12.1", "js-sys", "lazy_static", "libsecp256k1", "log", "memmap2", - "num-derive 0.4.2", + "num-derive", "num-traits", - "num_enum 0.7.2", - "pbkdf2 0.11.0", - "qstring", - "qualifier_attr", + "num_enum", + "pbkdf2", "rand 0.7.3", "rand 0.8.5", - "rustc_version", - "rustversion", "serde", "serde_bytes", "serde_derive", "serde_json", - "serde_with 2.3.3", + "serde_with", "sha2 0.10.8", - "sha3 0.10.8", + "sha3", "siphasher", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-logger", + "solana-account", + "solana-bn254", + "solana-decode-error", + "solana-derivation-path", + "solana-feature-set", + "solana-inflation", + "solana-instruction", + "solana-native-token", + "solana-packet", + "solana-precompile-error", "solana-program", + "solana-program-memory", + "solana-pubkey", + "solana-sanitize", "solana-sdk-macro", - "thiserror", - "uriparse", + "solana-secp256k1-recover", + "solana-secp256r1-program", + "solana-serde-varint", + "solana-short-vec", + "solana-signature", + "solana-transaction-error", + "thiserror 1.0.69", "wasm-bindgen", ] [[package]] name = "solana-sdk-macro" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cb099b2f9c0a65a6f23ced791325141cd68c27b04d11c04fef838a00f613861" +checksum = "85df4723291cfec8ffe9dadc59d565afcae12ea9a6460b7b28c4da21c2c4a887" dependencies = [ - "bs58 0.4.0", + "bs58", "proc-macro2", "quote", - "rustversion", - "syn 2.0.60", + "syn 2.0.90", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c38fc7bc33f78af99c4848c9a924b2b6e5d33d96f269d108777d982de72f73" +dependencies = [ + "borsh 1.5.3", + "libsecp256k1", + "solana-define-syscall", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-secp256r1-program" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5bbc17379248923203317b337ce871bbf1ba6c59f01c49dc65895ffdc684f0a" +dependencies = [ + "bytemuck", + "openssl", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-pubkey", ] [[package]] @@ -4552,13 +5049,14 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-send-transaction-service" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0deed4fe8bb31ff178d8b7e8295bc81e6e1d704fc0e2c5565f58d9eb8feec89d" +checksum = "c1f09eea5dbb0f2489799f337caf51243bc8d1a9277a90d8a1bf7c170ad86595" dependencies = [ "crossbeam-channel", "log", "solana-client", + "solana-connection-cache", "solana-measure", "solana-metrics", "solana-runtime", @@ -4566,73 +5064,228 @@ dependencies = [ "solana-tpu-client", ] +[[package]] +name = "solana-serde-varint" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2fc696c10a2b02356584cbd45d83d42b01b10256cb36b5d0c3768e5adf9283" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b04c6fb71e4cdd10480bc8d306aca6d2a7494e6267e4f103085a89b2ec04e4c" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4c977c6c4d95c8b43a9f405844f29a73c9d8b0a7c561b91d4f6a44f290d35c" +dependencies = [ + "sha2 0.10.8", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ca5799b37642e4e273d7d848564739eab45df670edcc61b4696ef0d5ebe4a8c" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-signature" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d28fe70f88bffb651a6ff8c37c236b935e97589865ca32e4a4544cdd10c7b268" +dependencies = [ + "bs58", + "ed25519-dalek", + "generic-array", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-sanitize", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e596d3719b4c03987de87c8cc25b34b6afcf7464c82b4d9c9b114304d882c97" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4022b0e8a7f043bd61504fff79176c02b52f69a69299023884b194a1405c0f05" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82f0665dfcfcb4433708abff54db5ee105fe1bb8db7fd409074bd0275582105" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + [[package]] name = "solana-stake-program" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea02d44b82ed0eb271871cf8a1b8179a0ab50f4f995e7d8ae691c1971bd0a0e" +checksum = "d582421c0cffbf5174965c4a45aa05e90d584b6b13688ea1a13e9d332e3e4f25" dependencies = [ "bincode", "log", - "rustc_version", "solana-config-program", + "solana-feature-set", + "solana-log-collector", "solana-program-runtime", "solana-sdk", + "solana-type-overrides", "solana-vote-program", ] [[package]] name = "solana-streamer" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a20843e8370adb3c04f47caa79ffdc92ae1bf078ad26530be1bca5d7bdd5d2" +checksum = "3173f4634b4e0acc366dec277744af50ffbf661dfe41291adf1406841a1b9c96" dependencies = [ "async-channel", "bytes", "crossbeam-channel", + "dashmap", + "futures", "futures-util", + "governor", "histogram", - "indexmap 2.2.6", - "itertools", + "indexmap", + "itertools 0.12.1", "libc", "log", "nix", "pem", "percentage", - "pkcs8", "quinn", "quinn-proto", "rand 0.8.5", - "rcgen", - "rustls", + "rustls 0.23.20", "smallvec", + "socket2", + "solana-measure", "solana-metrics", "solana-perf", "solana-sdk", - "thiserror", + "solana-transaction-metrics-tracker", + "thiserror 1.0.69", "tokio", + "tokio-util 0.7.10", "x509-parser", ] +[[package]] +name = "solana-svm" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bf9d2af384033d0eae21a55124858ced941856364316626cf974a94be14ae5" +dependencies = [ + "itertools 0.12.1", + "log", + "percentage", + "serde", + "serde_derive", + "solana-bpf-loader-program", + "solana-compute-budget", + "solana-feature-set", + "solana-fee", + "solana-loader-v4-program", + "solana-log-collector", + "solana-measure", + "solana-program-runtime", + "solana-runtime-transaction", + "solana-sdk", + "solana-svm-rent-collector", + "solana-svm-transaction", + "solana-system-program", + "solana-timings", + "solana-type-overrides", + "solana-vote", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-svm-rent-collector" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "813e8669142396c7898ce9439d1ebfcfbf7f2edfc79f6fcaa35a87060a4af3ff" +dependencies = [ + "solana-sdk", +] + +[[package]] +name = "solana-svm-transaction" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572fbc0b6fa828a7bfd2c7b3039f61c169981974f37882ca4fac138290be9ce0" +dependencies = [ + "solana-sdk", +] + [[package]] name = "solana-system-program" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01294e45b407b7d4c8ff546af6f60344efd6591cf162c88e231ee3ba2c544672" +checksum = "7d271fdd4194fcc7de75c724c05f3d4a7062dba6ef279c7e8bfbd694ef7fb7ab" dependencies = [ "bincode", "log", "serde", "serde_derive", + "solana-log-collector", "solana-program-runtime", "solana-sdk", + "solana-type-overrides", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbed7acdd711e0d620c9b7f788d041d35731c2c675d1d687498745d73826ca4" +dependencies = [ + "solana-pubkey", ] [[package]] name = "solana-thin-client" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c74da8f36b89b28c47e5ba3bad5279ff3dfea5829154882845d4821fc76ff497" +checksum = "9facb2fbf83b8a3acb1cb4523bffa3db7be838faf2cfda374f0d99120917d870" dependencies = [ "bincode", "log", @@ -4643,41 +5296,79 @@ dependencies = [ "solana-sdk", ] +[[package]] +name = "solana-timings" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6a83fbf8377e65d4c8e6a3c3c877c944a530ca9003f94389fd1528213c7c001" +dependencies = [ + "eager", + "enum-iterator", + "solana-sdk", +] + [[package]] name = "solana-tpu-client" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f2fd4b4aeffa14b9c5be9913072ea8e72ca261254a65a999f3d2fd70e7a660" +checksum = "31cb5c39698855b236b6266025b2f31b1948ee370cd53a5cca6c7c62eea3104d" dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap 2.2.6", + "indexmap", "indicatif", "log", "rayon", "solana-connection-cache", "solana-measure", - "solana-metrics", "solana-pubsub-client", "solana-rpc-client", "solana-rpc-client-api", "solana-sdk", - "thiserror", + "thiserror 1.0.69", "tokio", ] +[[package]] +name = "solana-transaction-error" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae45f064c8e6006a426b31a1182123ec4daf8cca50bd7aea6e796e6205a7911e" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-transaction-metrics-tracker" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb406ed0db097a5d2067c3c737bec3f515ea70a2cfa5abec8fc0606098049e42" +dependencies = [ + "base64 0.22.1", + "bincode", + "lazy_static", + "log", + "rand 0.8.5", + "solana-perf", + "solana-sdk", + "solana-short-vec", +] + [[package]] name = "solana-transaction-status" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3efa0d30f78dbc74e795638b053dd6ec7230739301e7f0e06b586f7731fd25c8" +checksum = "254b3f1295b8654604d1f1b2980a4ec81621c071cc7bcbb8b3e6eb44ce98e8b1" dependencies = [ "Inflector", - "base64 0.21.7", + "base64 0.22.1", "bincode", - "borsh 0.10.3", - "bs58 0.4.0", + "borsh 1.5.3", + "bs58", "lazy_static", "log", "serde", @@ -4685,94 +5376,165 @@ dependencies = [ "serde_json", "solana-account-decoder", "solana-sdk", + "solana-transaction-status-client-types", "spl-associated-token-account", "spl-memo", - "spl-token", + "spl-token 6.0.0", "spl-token-2022", - "thiserror", + "spl-token-group-interface", + "spl-token-metadata-interface", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a853cb1b1d5d1b521a51ae4666668f321505f0280839b00337d2620a9aba641" +dependencies = [ + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-sdk", + "solana-signature", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-type-overrides" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4347abe10a8290cb6b135b1e40115e4d390d29588fb5ba598be891a98d09e10d" +dependencies = [ + "lazy_static", + "rand 0.8.5", ] [[package]] name = "solana-udp-client" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32af58cadd37be19d04e0f3877104b8640bccc4be8ca1dbf431549b399b784c2" +checksum = "2b3064f000984b1f1032b3686577e452c423cbe3f8208efc713c16408f3a4086" dependencies = [ "async-trait", "solana-connection-cache", "solana-net-utils", "solana-sdk", "solana-streamer", - "thiserror", + "thiserror 1.0.69", "tokio", ] [[package]] name = "solana-version" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42c7cef8aa9f1c633bf09dd91b8e635b6b30c40236652031b1800b245dc1bd02" +checksum = "85b16c635fe2ccc3287bd5f84c6c86fbf316510df4229506d0bd9af50f2f1780" dependencies = [ - "log", - "rustc_version", "semver", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-sdk", + "solana-feature-set", + "solana-sanitize", + "solana-serde-varint", ] [[package]] name = "solana-vote" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12945ee508c751ffdce58f976be6e58a05529ce0032c1f7db76eed6a8d76b33c" +checksum = "228c93777a3ad6dc60abe422c558e8476ed0de4fe2b8784dfacb07951ca38355" dependencies = [ - "crossbeam-channel", - "itertools", + "itertools 0.12.1", "log", - "rustc_version", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", "solana-sdk", - "solana-vote-program", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "solana-vote-program" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725a39044d455c08fe83fca758e94e5ddfaa25f6e2e2cfd5c31d7afdcad8de38" +checksum = "94b556c4d1e742e8ab829bfa33b01cc22b823e7f42351e7ba24e4b2e26c3138f" dependencies = [ "bincode", "log", - "num-derive 0.4.2", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-feature-set", + "solana-metrics", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-zk-elgamal-proof-program" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c16a1e687c3f2f88785d8fb8e802dba2b46430f970cd61588fbd3a78371ef4" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk", + "solana-zk-sdk", +] + +[[package]] +name = "solana-zk-sdk" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea58ce4bcac4c6f3577ffc753b8bff3d259169bde1827b4466acb5daae088d2" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "js-sys", + "lazy_static", + "merlin", + "num-derive", "num-traits", - "rustc_version", + "rand 0.8.5", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-metrics", + "serde_json", + "sha3", + "solana-derivation-path", "solana-program", - "solana-program-runtime", "solana-sdk", - "thiserror", + "subtle", + "thiserror 1.0.69", + "wasm-bindgen", + "zeroize", ] [[package]] name = "solana-zk-token-proof-program" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39263f3e47a160b9b67896f2225d56e6872905c066152cbe61f5fd201c52a6d2" +checksum = "cdf2fd51bccc6be1173e4541f8a1390746e080d77165ee5fc40a9a390a82c55b" dependencies = [ "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", + "solana-feature-set", + "solana-log-collector", "solana-program-runtime", "solana-sdk", "solana-zk-token-sdk", @@ -4780,58 +5542,54 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.18.12" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630dc0b5f6250cf6a4c8b2bd3895283738915e83eba5453db20bb02b2527f302" +checksum = "f4340e5b7e4c3aa1d41ee638ab7d13eb1bcfc32d59c275a9f41838f059728aa6" dependencies = [ "aes-gcm-siv", - "base64 0.21.7", + "base64 0.22.1", "bincode", "bytemuck", + "bytemuck_derive", "byteorder", - "curve25519-dalek", - "getrandom 0.1.16", - "itertools", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", "lazy_static", "merlin", - "num-derive 0.4.2", + "num-derive", "num-traits", - "rand 0.7.3", + "rand 0.8.5", "serde", + "serde_derive", "serde_json", - "sha3 0.9.1", + "sha3", + "solana-curve25519", + "solana-derivation-path", "solana-program", "solana-sdk", "subtle", - "thiserror", + "thiserror 1.0.69", "zeroize", ] [[package]] name = "solana_rbpf" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" +checksum = "1c1941b5ef0c3ce8f2ac5dd984d0fb1a97423c4ff2a02eec81e3913f02e2ac2b" dependencies = [ "byteorder", - "combine", - "goblin", + "combine 3.8.1", "hash32", "libc", "log", "rand 0.8.5", "rustc-demangle", "scroll", - "thiserror", + "thiserror 1.0.69", "winapi", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -4839,36 +5597,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] -name = "spki" -version = "0.5.4" +name = "spinning_top" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" dependencies = [ - "base64ct", - "der", + "lock_api", ] [[package]] name = "spl-associated-token-account" -version = "2.3.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" +checksum = "68034596cf4804880d265f834af1ff2f821ad5293e41fa0f8f59086c181fc38e" dependencies = [ "assert_matches", - "borsh 0.10.3", - "num-derive 0.4.2", + "borsh 1.5.3", + "num-derive", "num-traits", "solana-program", - "spl-token", + "spl-token 6.0.0", "spl-token-2022", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "spl-discriminator" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa600f2fe56f32e923261719bae640d873edadbc5237681a39b8e37bfd4d263" +checksum = "a38ea8b6dedb7065887f12d62ed62c1743aa70749e8558f963609793f6fb12bc" dependencies = [ "bytemuck", "solana-program", @@ -4877,45 +5634,46 @@ dependencies = [ [[package]] name = "spl-discriminator-derive" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fd7858fc4ff8fb0e34090e41d7eb06a823e1057945c26d480bfc21d2338a93" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] name = "spl-discriminator-syn" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fea7be851bd98d10721782ea958097c03a0c2a07d8d4997041d0ece6319a63" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.60", - "thiserror", + "syn 2.0.90", + "thiserror 1.0.69", ] [[package]] name = "spl-memo" -version = "4.0.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" +checksum = "a0dba2f2bb6419523405d21c301a32c9f9568354d4742552e7972af801f4bdb3" dependencies = [ "solana-program", ] [[package]] name = "spl-pod" -version = "0.1.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5db7e4efb1107b0b8e52a13f035437cdcb36ef99c58f6d467f089d9b2915a" +checksum = "c704c88fc457fa649ba3aabe195c79d885c3f26709efaddc453c8de352c90b87" dependencies = [ - "borsh 0.10.3", + "borsh 1.5.3", "bytemuck", + "bytemuck_derive", "solana-program", "solana-zk-token-sdk", "spl-program-error", @@ -4923,34 +5681,34 @@ dependencies = [ [[package]] name = "spl-program-error" -version = "0.3.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e0657b6490196971d9e729520ba934911ff41fbb2cb9004463dbe23cf8b4b4f" +checksum = "d7b28bed65356558133751cc32b48a7a5ddfc59ac4e941314630bbed1ac10532" dependencies = [ - "num-derive 0.4.2", + "num-derive", "num-traits", "solana-program", "spl-program-error-derive", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "spl-program-error-derive" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1845dfe71fd68f70382232742e758557afe973ae19e6c06807b2c30f5d5cb474" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] name = "spl-tlv-account-resolution" -version = "0.5.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f335787add7fa711819f9e7c573f8145a5358a709446fe2d24bf2a88117c90" +checksum = "37a75a5f0fcc58126693ed78a17042e9dc53f07e357d6be91789f7d62aff61a4" dependencies = [ "bytemuck", "solana-program", @@ -4962,65 +5720,66 @@ dependencies = [ [[package]] name = "spl-token" -version = "4.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060" +checksum = "70a0f06ac7f23dc0984931b1fe309468f14ea58e32660439c1cef19456f5d0e3" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token" +version = "7.0.0" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.3.3", + "lazy_static", + "num-derive", "num-traits", - "num_enum 0.6.1", + "num_enum", + "proptest", + "serial_test", "solana-program", - "thiserror", + "solana-program-test", + "solana-sdk", + "thiserror 2.0.7", ] [[package]] name = "spl-token-2022" -version = "1.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" +checksum = "d9c10f3483e48679619c76598d4e4aebb955bc49b0a5cc63323afbf44135c9bf" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", - "num_enum 0.7.2", + "num_enum", "solana-program", "solana-security-txt", "solana-zk-token-sdk", "spl-memo", "spl-pod", - "spl-token", + "spl-token 6.0.0", "spl-token-group-interface", "spl-token-metadata-interface", "spl-transfer-hook-interface", "spl-type-length-value", - "thiserror", -] - -[[package]] -name = "spl-token-client" -version = "0.0.0" -dependencies = [ - "anchor-lang", - "assert_matches", - "borsh 0.10.3", - "num-derive 0.3.3", - "num-traits", - "serde", - "serde_with 3.8.1", - "solana-program", - "solana-program-test", - "solana-sdk", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "spl-token-group-interface" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" +checksum = "df8752b85a5ecc1d9f3a43bce3dd9a6a053673aacf5deb513d1cbb88d3534ffd" dependencies = [ "bytemuck", "solana-program", @@ -5031,11 +5790,11 @@ dependencies = [ [[package]] name = "spl-token-metadata-interface" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" +checksum = "c6c2318ddff97e006ed9b1291ebec0750a78547f870f62a69c56fe3b46a5d8fc" dependencies = [ - "borsh 0.10.3", + "borsh 1.5.3", "solana-program", "spl-discriminator", "spl-pod", @@ -5045,9 +5804,9 @@ dependencies = [ [[package]] name = "spl-transfer-hook-interface" -version = "0.4.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" +checksum = "a110f33d941275d9f868b96daaa993f1e73b6806cc8836e43075b4d3ad8338a7" dependencies = [ "arrayref", "bytemuck", @@ -5061,9 +5820,9 @@ dependencies = [ [[package]] name = "spl-type-length-value" -version = "0.3.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f9ebd75d29c5f48de5f6a9c114e08531030b75b8ac2c557600ac7da0b73b1e8" +checksum = "bdcd73ec187bc409464c60759232e309f83b52a18a9c5610bf281c9c6432918c" dependencies = [ "bytemuck", "solana-program", @@ -5073,16 +5832,16 @@ dependencies = [ ] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "stable_deref_trait" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "strsim" -version = "0.8.0" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" @@ -5105,7 +5864,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "rustversion", @@ -5114,9 +5873,9 @@ dependencies = [ [[package]] name = "subtle" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symlink" @@ -5137,27 +5896,15 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5176,6 +5923,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -5199,9 +5957,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.40" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", @@ -5224,7 +5982,7 @@ dependencies = [ "serde", "static_assertions", "tarpc-plugins", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-serde", "tokio-util 0.6.10", @@ -5243,14 +6001,24 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "task-local-extensions" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +dependencies = [ + "pin-utils", +] + [[package]] name = "tempfile" -version = "3.10.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", "windows-sys 0.52.0", ] @@ -5271,71 +6039,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] -name = "test-case" -version = "3.3.1" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "test-case-macros", + "thiserror-impl 1.0.69", ] [[package]] -name = "test-case-core" -version = "3.3.1" +name = "thiserror" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" +checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.60", + "thiserror-impl 2.0.7", ] [[package]] -name = "test-case-macros" -version = "3.3.1" +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", - "test-case-core", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" - -[[package]] -name = "thiserror" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" -dependencies = [ - "thiserror-impl", + "syn 2.0.90", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -5380,22 +6120,13 @@ dependencies = [ ] [[package]] -name = "tiny-bip39" -version = "0.8.2" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "anyhow", - "hmac 0.8.1", - "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", - "rustc-hash", - "sha2 0.9.9", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", + "displaydoc", + "zerovec", ] [[package]] @@ -5440,7 +6171,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -5449,7 +6180,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", "tokio", ] @@ -5471,9 +6202,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -5488,7 +6219,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", "tungstenite", @@ -5539,24 +6270,13 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow", -] - [[package]] name = "toml_edit" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.6", + "indexmap", "toml_datetime", "winnow", ] @@ -5587,7 +6307,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", ] [[package]] @@ -5643,9 +6363,9 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls", + "rustls 0.21.12", "sha1", - "thiserror", + "thiserror 1.0.69", "url", "utf-8", "webpki-roots 0.24.0", @@ -5658,31 +6378,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] -name = "unicode-bidi" -version = "0.3.15" +name = "unarray" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" +name = "unicase" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] -name = "unicode-segmentation" -version = "1.11.0" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" @@ -5698,11 +6409,11 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array", + "crypto-common", "subtle", ] @@ -5715,12 +6426,6 @@ dependencies = [ "void", ] -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -5739,9 +6444,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.0" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -5754,6 +6459,18 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "valuable" version = "0.1.0" @@ -5761,10 +6478,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] -name = "vec_map" -version = "0.8.2" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" @@ -5778,6 +6495,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -5811,26 +6537,26 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", "wasm-bindgen-shared", ] @@ -5848,9 +6574,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5858,22 +6584,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" @@ -5885,13 +6611,32 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd5da49bdf1f30054cfe0b8ce2958b8fbeb67c4d82c8967a598af481bef255c" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" dependencies = [ - "rustls-webpki", + "rustls-webpki 0.101.7", ] [[package]] @@ -6098,6 +6843,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "x509-parser" version = "0.14.0" @@ -6112,7 +6869,7 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -6128,12 +6885,27 @@ dependencies = [ ] [[package]] -name = "yasna" -version = "0.5.2" +name = "yoke" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ - "time", + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure 0.13.1", ] [[package]] @@ -6153,14 +6925,35 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure 0.13.1", ] [[package]] name = "zeroize" -version = "1.3.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -6173,25 +6966,46 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.90", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ - "libc", "zstd-sys", ] diff --git a/Cargo.toml b/Cargo.toml index 62b16bf..ec0aeab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,22 @@ [workspace] resolver = "2" -members = ["clients/rust"] +members = ["program"] + +[workspace.lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + 'cfg(target_os, values("solana"))', + 'cfg(feature, values("frozen-abi", "no-entrypoint"))', +] [workspace.metadata.cli] -solana = "1.18.18" +solana = "2.1.0" # Specify Rust toolchains for rustfmt, clippy, and build. # Any unprovided toolchains default to stable. [workspace.metadata.toolchains] -format = "1.78.0" -lint = "1.78.0" +format = "nightly-2024-08-08" +lint = "nightly-2024-08-08" + +[workspace.metadata.spellcheck] +config = "scripts/spellcheck.toml" diff --git a/clients/rust/Cargo.toml b/clients/rust/Cargo.toml index a6dc78d..c4aa3a1 100644 --- a/clients/rust/Cargo.toml +++ b/clients/rust/Cargo.toml @@ -8,21 +8,14 @@ readme = "README.md" license-file = "../../LICENSE" [features] -anchor = ["dep:anchor-lang"] test-sbf = [] serde = ["dep:serde", "dep:serde_with"] [dependencies] -anchor-lang = { version = "0.30.0", optional = true } borsh = "^0.10" num-derive = "^0.3" num-traits = "^0.2" serde = { version = "^1.0", features = ["derive"], optional = true } serde_with = { version = "^3.0", optional = true } -solana-program = "~1.18" +solana-program = "2.1" thiserror = "^1.0" - -[dev-dependencies] -assert_matches = "1.5.0" -solana-program-test = "~1.18" -solana-sdk = "~1.18" diff --git a/clients/rust/src/lib.rs b/clients/rust/src/lib.rs index bae91ca..0335589 100644 --- a/clients/rust/src/lib.rs +++ b/clients/rust/src/lib.rs @@ -1,4 +1,6 @@ +/* mod generated; pub use generated::programs::TOKEN_ID as ID; pub use generated::*; +*/ diff --git a/package.json b/package.json index e9eb954..9a3d3fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,10 @@ { "private": true, "scripts": { + "programs:build": "zx ./scripts/rust/build-sbf.mjs program", + "programs:format": "zx ./scripts/rust/format.mjs program", + "programs:lint": "zx ./scripts/rust/lint.mjs program", + "programs:test": "zx ./scripts/rust/test-sbf.mjs program", "solana:check": "zx ./scripts/check-solana-version.mjs", "solana:link": "zx ./scripts/link-solana-version.mjs", "generate": "pnpm generate:clients", @@ -8,15 +12,18 @@ "validator:start": "zx ./scripts/start-validator.mjs", "validator:restart": "pnpm validator:start --restart", "validator:stop": "zx ./scripts/stop-validator.mjs", - "clients:js:format": "zx ./scripts/client/format-js.mjs", - "clients:js:lint": "zx ./scripts/client/lint-js.mjs", - "clients:js:publish": "zx ./scripts/client/publish-js.mjs", - "clients:js:test": "zx ./scripts/client/test-js.mjs", - "clients:rust:format": "zx ./scripts/client/format-rust.mjs", - "clients:rust:lint": "zx ./scripts/client/lint-rust.mjs", - "clients:rust:publish": "zx ./scripts/client/publish-rust.mjs", - "clients:rust:test": "zx ./scripts/client/test-rust.mjs", - "template:upgrade": "zx ./scripts/upgrade-template.mjs" + "clients:js:format": "zx ./scripts/js/format.mjs", + "clients:js:lint": "zx ./scripts/js/lint.mjs", + "clients:js:publish": "zx ./scripts/js/publish.mjs", + "clients:js:test": "zx ./scripts/js/test.mjs", + "clients:rust:format": "zx ./scripts/rust/format.mjs clients/rust", + "clients:rust:lint": "zx ./scripts/rust/lint.mjs clients/rust", + "clients:rust:publish": "zx ./scripts/rust/publish.mjs clients/rust", + "clients:rust:test": "zx ./scripts/rust/test-sbf.mjs clients/rust", + "template:upgrade": "zx ./scripts/upgrade-template.mjs", + "rust:spellcheck": "cargo spellcheck --code 1", + "rust:audit": "zx ./scripts/rust/audit.mjs", + "rust:semver": "cargo semver-checks" }, "devDependencies": { "@codama/renderers-js": "^1.0.0", diff --git a/program/Cargo.toml b/program/Cargo.toml index 5a7f867..cfff306 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -2,11 +2,10 @@ name = "spl-token" version = "7.0.0" description = "Solana Program Library Token" -authors = ["Solana Labs Maintainers "] -repository = "https://github.com/solana-labs/solana-program-library" +authors = ["Anza Maintainers "] +repository = "https://github.com/solana-program/token" license = "Apache-2.0" edition = "2021" -exclude = ["js/**"] [features] no-entrypoint = [] @@ -36,3 +35,6 @@ targets = ["x86_64-unknown-linux-gnu"] [lints] workspace = true + +[package.metadata.solana] +program-id = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" diff --git a/program/Xargo.toml b/program/Xargo.toml deleted file mode 100644 index 1744f09..0000000 --- a/program/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] \ No newline at end of file diff --git a/program/inc/token.h b/program/inc/token.h deleted file mode 100644 index 145c0c5..0000000 --- a/program/inc/token.h +++ /dev/null @@ -1,687 +0,0 @@ -/* Autogenerated SPL Token program C Bindings */ - -#pragma once - -#include -#include -#include -#include - -/** - * Minimum number of multisignature signers (min N) - */ -#define Token_MIN_SIGNERS 1 - -/** - * Maximum number of multisignature signers (max N) - */ -#define Token_MAX_SIGNERS 11 - -/** - * Account state. - */ -enum Token_AccountState -#ifdef __cplusplus - : uint8_t -#endif // __cplusplus - { - /** - * Account is not yet initialized - */ - Token_AccountState_Uninitialized, - /** - * Account is initialized; the account owner and/or delegate may perform permitted operations - * on this account - */ - Token_AccountState_Initialized, - /** - * Account has been frozen by the mint freeze authority. Neither the account owner nor - * the delegate are able to perform operations on this account. - */ - Token_AccountState_Frozen, -}; -#ifndef __cplusplus -typedef uint8_t Token_AccountState; -#endif // __cplusplus - -/** - * Specifies the authority type for SetAuthority instructions - */ -enum Token_AuthorityType -#ifdef __cplusplus - : uint8_t -#endif // __cplusplus - { - /** - * Authority to mint new tokens - */ - Token_AuthorityType_MintTokens, - /** - * Authority to freeze any account associated with the Mint - */ - Token_AuthorityType_FreezeAccount, - /** - * Owner of a given token account - */ - Token_AuthorityType_AccountOwner, - /** - * Authority to close a token account - */ - Token_AuthorityType_CloseAccount, -}; -#ifndef __cplusplus -typedef uint8_t Token_AuthorityType; -#endif // __cplusplus - -typedef uint8_t Token_Pubkey[32]; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_Pubkey_Tag { - /** - * No value - */ - Token_COption_Pubkey_None_Pubkey, - /** - * Some value `T` - */ - Token_COption_Pubkey_Some_Pubkey, -} Token_COption_Pubkey_Tag; - -typedef struct Token_COption_Pubkey { - Token_COption_Pubkey_Tag tag; - union { - struct { - Token_Pubkey some; - }; - }; -} Token_COption_Pubkey; - -/** - * Instructions supported by the token program. - */ -typedef enum Token_TokenInstruction_Tag { - /** - * Initializes a new mint and optionally deposits all the newly minted - * tokens in an account. - * - * The `InitializeMint` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The mint to initialize. - * 1. `[]` Rent sysvar - * - */ - Token_TokenInstruction_InitializeMint, - /** - * Initializes a new account to hold tokens. If this account is associated - * with the native mint then the token balance of the initialized account - * will be equal to the amount of SOL in the account. If this account is - * associated with another mint, that mint must be initialized before this - * command can succeed. - * - * The `InitializeAccount` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The account to initialize. - * 1. `[]` The mint this account will be associated with. - * 2. `[]` The new account's owner/multisignature. - * 3. `[]` Rent sysvar - */ - Token_TokenInstruction_InitializeAccount, - /** - * Initializes a multisignature account with N provided signers. - * - * Multisignature accounts can used in place of any single owner/delegate - * accounts in any token instruction that require an owner/delegate to be - * present. The variant field represents the number of signers (M) - * required to validate this multisignature account. - * - * The `InitializeMultisig` instruction requires no signers and MUST be - * included within the same Transaction as the system program's - * `CreateAccount` instruction that creates the account being initialized. - * Otherwise another party can acquire ownership of the uninitialized - * account. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The multisignature account to initialize. - * 1. `[]` Rent sysvar - * 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= - * 11. - */ - Token_TokenInstruction_InitializeMultisig, - /** - * Transfers tokens from one account to another either directly or via a - * delegate. If this account is associated with the native mint then equal - * amounts of SOL and Tokens will be transferred to the destination - * account. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The source account. - * 1. `[writable]` The destination account. - * 2. `[signer]` The source account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The source account. - * 1. `[writable]` The destination account. - * 2. `[]` The source account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_Transfer, - /** - * Approves a delegate. A delegate is given the authority over tokens on - * behalf of the source account's owner. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[]` The delegate. - * 2. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The delegate. - * 2. `[]` The source account's multisignature owner. - * 3. ..3+M `[signer]` M signer accounts - */ - Token_TokenInstruction_Approve, - /** - * Revokes the delegate's authority. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The source account's multisignature owner. - * 2. ..2+M `[signer]` M signer accounts - */ - Token_TokenInstruction_Revoke, - /** - * Sets a new authority of a mint or account. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint or account to change the authority of. - * 1. `[signer]` The current authority of the mint or account. - * - * * Multisignature authority - * 0. `[writable]` The mint or account to change the authority of. - * 1. `[]` The mint's or account's current multisignature authority. - * 2. ..2+M `[signer]` M signer accounts - */ - Token_TokenInstruction_SetAuthority, - /** - * Mints new tokens to an account. The native mint does not support - * minting. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's minting authority. - * - * * Multisignature authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature mint-tokens authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_MintTo, - /** - * Burns tokens by removing them from an account. `Burn` does not support - * accounts associated with the native mint, use `CloseAccount` instead. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[signer]` The account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_Burn, - /** - * Close an account by transferring all its SOL to the destination account. - * Non-native accounts may only be closed if its token amount is zero. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to close. - * 1. `[writable]` The destination account. - * 2. `[signer]` The account's owner. - * - * * Multisignature owner - * 0. `[writable]` The account to close. - * 1. `[writable]` The destination account. - * 2. `[]` The account's multisignature owner. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_CloseAccount, - /** - * Freeze an Initialized account using the Mint's freeze_authority (if - * set). - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[signer]` The mint freeze authority. - * - * * Multisignature owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[]` The mint's multisignature freeze authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_FreezeAccount, - /** - * Thaw a Frozen account using the Mint's freeze_authority (if set). - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[signer]` The mint freeze authority. - * - * * Multisignature owner - * 0. `[writable]` The account to freeze. - * 1. `[]` The token mint. - * 2. `[]` The mint's multisignature freeze authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_ThawAccount, - /** - * Transfers tokens from one account to another either directly or via a - * delegate. If this account is associated with the native mint then equal - * amounts of SOL and Tokens will be transferred to the destination - * account. - * - * This instruction differs from Transfer in that the token mint and - * decimals value is checked by the caller. This may be useful when - * creating transactions offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[writable]` The destination account. - * 3. `[signer]` The source account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[writable]` The destination account. - * 3. `[]` The source account's multisignature owner/delegate. - * 4. ..4+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_TransferChecked, - /** - * Approves a delegate. A delegate is given the authority over tokens on - * behalf of the source account's owner. - * - * This instruction differs from Approve in that the token mint and - * decimals value is checked by the caller. This may be useful when - * creating transactions offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[]` The delegate. - * 3. `[signer]` The source account owner. - * - * * Multisignature owner - * 0. `[writable]` The source account. - * 1. `[]` The token mint. - * 2. `[]` The delegate. - * 3. `[]` The source account's multisignature owner. - * 4. ..4+M `[signer]` M signer accounts - */ - Token_TokenInstruction_ApproveChecked, - /** - * Mints new tokens to an account. The native mint does not support - * minting. - * - * This instruction differs from MintTo in that the decimals value is - * checked by the caller. This may be useful when creating transactions - * offline or within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[signer]` The mint's minting authority. - * - * * Multisignature authority - * 0. `[writable]` The mint. - * 1. `[writable]` The account to mint tokens to. - * 2. `[]` The mint's multisignature mint-tokens authority. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_MintToChecked, - /** - * Burns tokens by removing them from an account. `BurnChecked` does not - * support accounts associated with the native mint, use `CloseAccount` - * instead. - * - * This instruction differs from Burn in that the decimals value is checked - * by the caller. This may be useful when creating transactions offline or - * within a hardware wallet. - * - * Accounts expected by this instruction: - * - * * Single owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[signer]` The account's owner/delegate. - * - * * Multisignature owner/delegate - * 0. `[writable]` The account to burn from. - * 1. `[writable]` The token mint. - * 2. `[]` The account's multisignature owner/delegate. - * 3. ..3+M `[signer]` M signer accounts. - */ - Token_TokenInstruction_BurnChecked, - /** - * Like InitializeAccount, but the owner pubkey is passed via instruction data - * rather than the accounts list. This variant may be preferable when using - * Cross Program Invocation from an instruction that does not need the owner's - * `AccountInfo` otherwise. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The account to initialize. - * 1. `[]` The mint this account will be associated with. - * 3. `[]` Rent sysvar - */ - Token_TokenInstruction_InitializeAccount2, - /** - * Given a wrapped / native token account (a token account containing SOL) - * updates its amount field based on the account's underlying `lamports`. - * This is useful if a non-wrapped SOL account uses `system_instruction::transfer` - * to move lamports to a wrapped token account, and needs to have its token - * `amount` field updated. - * - * Accounts expected by this instruction: - * - * 0. `[writable]` The native token account to sync with its underlying lamports. - */ - Token_TokenInstruction_SyncNative, -} Token_TokenInstruction_Tag; - -typedef struct Token_TokenInstruction_Token_InitializeMint_Body { - /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; - /** - * The authority/multisignature to mint tokens. - */ - Token_Pubkey mint_authority; - /** - * The freeze authority/multisignature of the mint. - */ - struct Token_COption_Pubkey freeze_authority; -} Token_TokenInstruction_Token_InitializeMint_Body; - -typedef struct Token_TokenInstruction_Token_InitializeMultisig_Body { - /** - * The number of signers (M) required to validate this multisignature - * account. - */ - uint8_t m; -} Token_TokenInstruction_Token_InitializeMultisig_Body; - -typedef struct Token_TokenInstruction_Token_Transfer_Body { - /** - * The amount of tokens to transfer. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Transfer_Body; - -typedef struct Token_TokenInstruction_Token_Approve_Body { - /** - * The amount of tokens the delegate is approved for. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Approve_Body; - -typedef struct Token_TokenInstruction_Token_SetAuthority_Body { - /** - * The type of authority to update. - */ - Token_AuthorityType authority_type; - /** - * The new authority - */ - struct Token_COption_Pubkey new_authority; -} Token_TokenInstruction_Token_SetAuthority_Body; - -typedef struct Token_TokenInstruction_Token_MintTo_Body { - /** - * The amount of new tokens to mint. - */ - uint64_t amount; -} Token_TokenInstruction_Token_MintTo_Body; - -typedef struct Token_TokenInstruction_Token_Burn_Body { - /** - * The amount of tokens to burn. - */ - uint64_t amount; -} Token_TokenInstruction_Token_Burn_Body; - -typedef struct Token_TokenInstruction_Token_TransferChecked_Body { - /** - * The amount of tokens to transfer. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_TransferChecked_Body; - -typedef struct Token_TokenInstruction_Token_ApproveChecked_Body { - /** - * The amount of tokens the delegate is approved for. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_ApproveChecked_Body; - -typedef struct Token_TokenInstruction_Token_MintToChecked_Body { - /** - * The amount of new tokens to mint. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_MintToChecked_Body; - -typedef struct Token_TokenInstruction_Token_BurnChecked_Body { - /** - * The amount of tokens to burn. - */ - uint64_t amount; - /** - * Expected number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; -} Token_TokenInstruction_Token_BurnChecked_Body; - -typedef struct Token_TokenInstruction_Token_InitializeAccount2_Body { - /** - * The new account's owner/multisignature. - */ - Token_Pubkey owner; -} Token_TokenInstruction_Token_InitializeAccount2_Body; - -typedef struct Token_TokenInstruction { - Token_TokenInstruction_Tag tag; - union { - Token_TokenInstruction_Token_InitializeMint_Body initialize_mint; - Token_TokenInstruction_Token_InitializeMultisig_Body initialize_multisig; - Token_TokenInstruction_Token_Transfer_Body transfer; - Token_TokenInstruction_Token_Approve_Body approve; - Token_TokenInstruction_Token_SetAuthority_Body set_authority; - Token_TokenInstruction_Token_MintTo_Body mint_to; - Token_TokenInstruction_Token_Burn_Body burn; - Token_TokenInstruction_Token_TransferChecked_Body transfer_checked; - Token_TokenInstruction_Token_ApproveChecked_Body approve_checked; - Token_TokenInstruction_Token_MintToChecked_Body mint_to_checked; - Token_TokenInstruction_Token_BurnChecked_Body burn_checked; - Token_TokenInstruction_Token_InitializeAccount2_Body initialize_account2; - }; -} Token_TokenInstruction; - -/** - * Mint data. - */ -typedef struct Token_Mint { - /** - * Optional authority used to mint new tokens. The mint authority may only be provided during - * mint creation. If no mint authority is present then the mint has a fixed supply and no - * further tokens may be minted. - */ - struct Token_COption_Pubkey mint_authority; - /** - * Total supply of tokens. - */ - uint64_t supply; - /** - * Number of base 10 digits to the right of the decimal place. - */ - uint8_t decimals; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; - /** - * Optional authority to freeze token accounts. - */ - struct Token_COption_Pubkey freeze_authority; -} Token_Mint; - -/** - * A C representation of Rust's `std::option::Option` - */ -typedef enum Token_COption_u64_Tag { - /** - * No value - */ - Token_COption_u64_None_u64, - /** - * Some value `T` - */ - Token_COption_u64_Some_u64, -} Token_COption_u64_Tag; - -typedef struct Token_COption_u64 { - Token_COption_u64_Tag tag; - union { - struct { - uint64_t some; - }; - }; -} Token_COption_u64; - -/** - * Account data. - */ -typedef struct Token_Account { - /** - * The mint associated with this account - */ - Token_Pubkey mint; - /** - * The owner of this account. - */ - Token_Pubkey owner; - /** - * The amount of tokens this account holds. - */ - uint64_t amount; - /** - * If `delegate` is `Some` then `delegated_amount` represents - * the amount authorized by the delegate - */ - struct Token_COption_Pubkey delegate; - /** - * The account's state - */ - Token_AccountState state; - /** - * If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account - * is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped - * SOL accounts do not drop below this threshold. - */ - struct Token_COption_u64 is_native; - /** - * The amount delegated - */ - uint64_t delegated_amount; - /** - * Optional authority to close the account. - */ - struct Token_COption_Pubkey close_authority; -} Token_Account; - -/** - * Multisignature data. - */ -typedef struct Token_Multisig { - /** - * Number of signers required - */ - uint8_t m; - /** - * Number of valid signers - */ - uint8_t n; - /** - * Is `true` if this structure has been initialized - */ - bool is_initialized; - /** - * Signer public keys - */ - Token_Pubkey signers[Token_MAX_SIGNERS]; -} Token_Multisig; diff --git a/program/program-id.md b/program/program-id.md deleted file mode 100644 index f397edf..0000000 --- a/program/program-id.md +++ /dev/null @@ -1 +0,0 @@ -TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..1de01fa --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.81.0" diff --git a/rustfmt.toml b/rustfmt.toml index 36789f4..1681821 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,10 +1,5 @@ -max_width = 100 -reorder_imports = true -reorder_modules = true - -# == Nightly only. == -# imports_indent = "Block" -# imports_layout = "Mixed" -# imports_granularity = "Crate" -# group_imports = "Preserve" -# reorder_impl_items = false +comment_width = 80 +edition = "2021" +group_imports = "One" +imports_granularity = "One" +wrap_comments = true diff --git a/scripts/client/test-rust.mjs b/scripts/client/test-rust.mjs deleted file mode 100644 index 699acb1..0000000 --- a/scripts/client/test-rust.mjs +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env zx -import 'zx/globals'; -import { cliArguments, workingDirectory } from '../utils.mjs'; - -// Configure additional arguments here, e.g.: -// ['--arg1', '--arg2', ...cliArguments()] -const testArgs = cliArguments(); - -const hasSolfmt = await which('solfmt', { nothrow: true }); -const sbfOutDir = path.join(workingDirectory, 'target', 'deploy'); - -// Run the tests. -cd(path.join(workingDirectory, 'clients', 'rust')); -if (hasSolfmt) { - await $`SBF_OUT_DIR=${sbfOutDir} cargo test --features "test-sbf" ${testArgs} 2>&1 | solfmt`; -} else { - await $`SBF_OUT_DIR=${sbfOutDir} cargo test --features "test-sbf" ${testArgs}`; -} diff --git a/scripts/client/format-js.mjs b/scripts/js/format.mjs similarity index 100% rename from scripts/client/format-js.mjs rename to scripts/js/format.mjs diff --git a/scripts/client/lint-js.mjs b/scripts/js/lint.mjs similarity index 100% rename from scripts/client/lint-js.mjs rename to scripts/js/lint.mjs diff --git a/scripts/client/publish-js.mjs b/scripts/js/publish.mjs similarity index 100% rename from scripts/client/publish-js.mjs rename to scripts/js/publish.mjs diff --git a/scripts/client/test-js.mjs b/scripts/js/test.mjs similarity index 100% rename from scripts/client/test-js.mjs rename to scripts/js/test.mjs diff --git a/scripts/rust/audit.mjs b/scripts/rust/audit.mjs new file mode 100644 index 0000000..43bd2cf --- /dev/null +++ b/scripts/rust/audit.mjs @@ -0,0 +1,31 @@ +#!/usr/bin/env zx +import 'zx/globals'; + +const advisories = [ + // ed25519-dalek: Double Public Key Signing Function Oracle Attack + // + // Remove once repo upgrades to ed25519-dalek v2 + 'RUSTSEC-2022-0093', + + // curve25519-dalek + // + // Remove once repo upgrades to curve25519-dalek v4 + 'RUSTSEC-2024-0344', + + // Crate: tonic + // Version: 0.9.2 + // Title: Remotely exploitable Denial of Service in Tonic + // Date: 2024-10-01 + // ID: RUSTSEC-2024-0376 + // URL: https://rustsec.org/advisories/RUSTSEC-2024-0376 + // Solution: Upgrade to >=0.12.3 + 'RUSTSEC-2024-0376', +]; +const ignores = [] +advisories.forEach(x => { + ignores.push('--ignore'); + ignores.push(x); +}); + +// Check Solana version. +await $`cargo audit ${ignores}`; diff --git a/scripts/rust/build-sbf.mjs b/scripts/rust/build-sbf.mjs new file mode 100644 index 0000000..cb2cbda --- /dev/null +++ b/scripts/rust/build-sbf.mjs @@ -0,0 +1,8 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, workingDirectory } from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); +await $`cargo-build-sbf --manifest-path ${manifestPath} ${args}`; + diff --git a/scripts/client/format-rust.mjs b/scripts/rust/format.mjs similarity index 72% rename from scripts/client/format-rust.mjs rename to scripts/rust/format.mjs index 038a832..de9518e 100644 --- a/scripts/client/format-rust.mjs +++ b/scripts/rust/format.mjs @@ -8,19 +8,13 @@ import { workingDirectory, } from '../utils.mjs'; -// Configure additional arguments here, e.g.: -// ['--arg1', '--arg2', ...cliArguments()] -const formatArgs = cliArguments(); +const [folder, ...formatArgs] = cliArguments(); const fix = popArgument(formatArgs, '--fix'); const [cargoArgs, fmtArgs] = partitionArguments(formatArgs, '--'); const toolchain = getToolchainArgument('format'); -const manifestPath = path.join( - workingDirectory, - 'clients', - 'rust', - 'Cargo.toml' -); + +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); // Format the client. if (fix) { diff --git a/scripts/client/lint-rust.mjs b/scripts/rust/lint.mjs similarity index 66% rename from scripts/client/lint-rust.mjs rename to scripts/rust/lint.mjs index 0b4a4e6..324850e 100644 --- a/scripts/client/lint-rust.mjs +++ b/scripts/rust/lint.mjs @@ -7,18 +7,23 @@ import { workingDirectory, } from '../utils.mjs'; +const [folder, ...args] = cliArguments(); + // Configure additional arguments here, e.g.: // ['--arg1', '--arg2', ...cliArguments()] -const lintArgs = cliArguments(); +const lintArgs = [ + '-Zunstable-options', + '--all-targets', + '--all-features', + '--', + '--deny=warnings', + '--deny=clippy::arithmetic_side_effects', + ...args, +]; const fix = popArgument(lintArgs, '--fix'); const toolchain = getToolchainArgument('lint'); -const manifestPath = path.join( - workingDirectory, - 'clients', - 'rust', - 'Cargo.toml' -); +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); // Check the client using Clippy. if (fix) { diff --git a/scripts/client/publish-rust.mjs b/scripts/rust/publish.mjs similarity index 100% rename from scripts/client/publish-rust.mjs rename to scripts/rust/publish.mjs diff --git a/scripts/rust/test-sbf.mjs b/scripts/rust/test-sbf.mjs new file mode 100644 index 0000000..1c11835 --- /dev/null +++ b/scripts/rust/test-sbf.mjs @@ -0,0 +1,8 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, workingDirectory } from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); +const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); + +await $`RUST_LOG=error cargo test-sbf --manifest-path ${manifestPath} ${args}`; diff --git a/scripts/solana.dic b/scripts/solana.dic new file mode 100644 index 0000000..2530ee1 --- /dev/null +++ b/scripts/solana.dic @@ -0,0 +1,51 @@ +1000 +config +metadata +json +uri +ui +cli +readme/S +arg/S +vec/S +enum/S +noop/S +realloc/S +overallocate/SGD +namespace +serde +deserialize/SRGD +deserialization +struct/S +param/S +tuple/S +metas +infos +async +subcommand +repo +init +solana +sol/S +blockchain/S +permissionless +composability +runtime +onchain +offchain +keypair/S +decrypt/SGD +lamport/S +validator/S +pubkey/S +sysvar/S +timestamp/S +entrypoint/S +spl +pda/S +multisignature/S +multisig/S +staker/S +APY +codama +autogenerated diff --git a/scripts/spellcheck.toml b/scripts/spellcheck.toml new file mode 100644 index 0000000..67d80b0 --- /dev/null +++ b/scripts/spellcheck.toml @@ -0,0 +1,6 @@ +[Hunspell] +use_builtin = true +skip_os_lookups = false +search_dirs = ["."] +extra_dictionaries = ["solana.dic"] + From 1c20ad58cf0ef2a55d9aa5f00711417224adeaad Mon Sep 17 00:00:00 2001 From: Jon C Date: Thu, 19 Dec 2024 12:12:07 +0100 Subject: [PATCH 258/335] CI: Add dependabot auto-merge (#15) CI: Add dependabot #### Problem Dependabot is not configured to merge PRs automatically on the repo. #### Summary of changes Add dependabot config. --- .github/workflows/dependabot-auto-merge.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/dependabot-auto-merge.yml diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..76cbcfb --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,17 @@ +name: Dependabot auto-merge +on: pull_request + +permissions: + contents: write + pull-requests: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository_owner == 'solana-program' + steps: + - name: Enable auto-merge + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 62ff9d3ca0651b245ec281af68bd50302bff84b8 Mon Sep 17 00:00:00 2001 From: Joe C Date: Thu, 19 Dec 2024 19:20:49 +0800 Subject: [PATCH 259/335] program: rewrite crate tests in mollusk (#14) --- Cargo.lock | 4143 +++------------------ program/Cargo.toml | 2 +- program/tests/action.rs | 140 - program/tests/assert_instruction_count.rs | 423 +-- program/tests/close_account.rs | 257 +- program/tests/setup.rs | 69 + 6 files changed, 840 insertions(+), 4194 deletions(-) delete mode 100644 program/tests/action.rs create mode 100644 program/tests/setup.rs diff --git a/Cargo.lock b/Cargo.lock index e776334..48b0c96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,83 +2,21 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm-siv" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "polyval", - "subtle", - "zeroize", -] - -[[package]] -name = "agave-transaction-view" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e479181a1b6702e9d85e213757646c9011b525a3489101ed887b3fbae182659b" -dependencies = [ - "solana-sdk", - "solana-svm-transaction", -] - [[package]] name = "ahash" version = "0.8.11" @@ -86,7 +24,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.14", "once_cell", "version_check", "zerocopy", @@ -116,41 +53,6 @@ dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" - -[[package]] -name = "aquamarine" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" -dependencies = [ - "include_dir", - "itertools 0.10.5", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "ark-bn254" version = "0.4.0" @@ -276,9 +178,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii" @@ -286,67 +188,11 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" -[[package]] -name = "asn1-rs" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror 1.0.69", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure 0.12.6", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - [[package]] name = "async-compression" -version = "0.4.9" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9eabd7a98fe442131a17c316bd9349c43695e49e730c3c8e12cfb5f4da2693" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "brotli", "flate2", @@ -356,58 +202,36 @@ dependencies = [ "tokio", ] -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.3.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-trait" -version = "0.1.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.2", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -416,12 +240,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -473,15 +291,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitmaps" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" -dependencies = [ - "typenum", -] - [[package]] name = "blake3" version = "1.5.5" @@ -516,11 +325,11 @@ dependencies = [ [[package]] name = "borsh" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" dependencies = [ - "borsh-derive 0.10.3", + "borsh-derive 0.10.4", "hashbrown 0.13.2", ] @@ -536,9 +345,9 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", @@ -554,7 +363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" dependencies = [ "once_cell", - "proc-macro-crate 3.1.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.90", @@ -562,9 +371,9 @@ dependencies = [ [[package]] name = "borsh-derive-internal" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" dependencies = [ "proc-macro2", "quote", @@ -573,9 +382,9 @@ dependencies = [ [[package]] name = "borsh-schema-derive-internal" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" dependencies = [ "proc-macro2", "quote", @@ -584,9 +393,9 @@ dependencies = [ [[package]] name = "brotli" -version = "5.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19483b140a7ac7174d34b5a581b406c64f84da5409d3e09cf4fff604f9270e67" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -595,9 +404,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -660,54 +469,15 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "caps" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" -dependencies = [ - "libc", - "thiserror 1.0.69", -] - [[package]] name = "cc" version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ - "jobserver", - "libc", "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-if" version = "1.0.0" @@ -733,36 +503,11 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.52.5", -] - -[[package]] -name = "chrono-humanize" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" -dependencies = [ - "chrono", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", ] [[package]] @@ -778,38 +523,6 @@ dependencies = [ "unreachable", ] -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "console" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.52.0", -] - [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -848,24 +561,24 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -879,30 +592,11 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -917,7 +611,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.4", "typenum", ] @@ -931,20 +624,11 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - [[package]] name = "curve25519-dalek" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" dependencies = [ "byteorder", "digest 0.9.0", @@ -984,9 +668,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -994,9 +678,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", @@ -1008,58 +692,15 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", "syn 2.0.90", ] -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", - "rayon", -] - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "der-parser" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint 0.4.6", - "num-traits", - "rusticata-macros", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - [[package]] name = "derivation-path" version = "0.2.0" @@ -1077,12 +718,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "difflib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" - [[package]] name = "digest" version = "0.9.0" @@ -1103,55 +738,17 @@ dependencies = [ "subtle", ] -[[package]] -name = "dir-diff" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" -dependencies = [ - "walkdir", -] - [[package]] name = "displaydoc" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "dlopen2" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.3.0" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn 2.0.90", ] -[[package]] -name = "downcast" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" - [[package]] name = "eager" version = "0.1.0" @@ -1173,7 +770,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek 3.2.0", + "curve25519-dalek 3.2.1", "ed25519", "rand 0.7.3", "serde", @@ -1193,35 +790,17 @@ dependencies = [ "sha2 0.10.8", ] -[[package]] -name = "educe" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "either" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" - -[[package]] -name = "encode_unicode" -version = "0.3.6" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -1237,23 +816,10 @@ dependencies = [ [[package]] name = "enum-iterator-derive" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19cbb53d33b57ac4df1f0af6b92c38c107cded663c4aea9fae1189dcfc17cf5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "enum-ordinalize" -version = "3.1.15" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ - "num-bigint 0.4.6", - "num-traits", "proc-macro2", "quote", "syn 2.0.90", @@ -1285,34 +851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" -dependencies = [ - "event-listener 5.3.1", - "pin-project-lite", + "windows-sys 0.59.0", ] [[package]] @@ -1333,18 +872,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "filetime" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", -] - [[package]] name = "five8_const" version = "0.1.3" @@ -1367,16 +894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", -] - -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", + "miniz_oxide", ] [[package]] @@ -1385,21 +903,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1409,12 +912,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fragile" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" - [[package]] name = "futures" version = "0.3.31" @@ -1463,17 +960,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "futures-sink" version = "0.3.31" @@ -1486,12 +972,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - [[package]] name = "futures-util" version = "0.3.31" @@ -1501,7 +981,6 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1546,9 +1025,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -1559,29 +1038,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "governor" -version = "0.6.3" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" -dependencies = [ - "cfg-if", - "dashmap", - "futures", - "futures-timer", - "no-std-compat", - "nonzero_ext", - "parking_lot", - "portable-atomic", - "quanta", - "rand 0.8.5", - "smallvec", - "spinning_top", -] +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "h2" @@ -1598,7 +1057,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.10", + "tokio-util", "tracing", ] @@ -1620,24 +1079,12 @@ dependencies = [ "ahash", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "hermit-abi" version = "0.1.19" @@ -1647,18 +1094,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "histogram" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" - [[package]] name = "hmac" version = "0.8.1" @@ -1713,9 +1148,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -1731,9 +1166,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -1762,34 +1197,11 @@ dependencies = [ "futures-util", "http", "hyper", - "rustls 0.21.12", + "rustls", "tokio", "tokio-rustls", ] -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" version = "1.5.0" @@ -1935,47 +1347,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "im" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" -dependencies = [ - "bitmaps", - "rand_core 0.6.4", - "rand_xoshiro", - "rayon", - "serde", - "sized-chunks", - "typenum", - "version_check", -] - -[[package]] -name = "include_dir" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" -dependencies = [ - "include_dir_macros", -] - -[[package]] -name = "include_dir_macros" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "index_list" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa38453685e5fe724fd23ff6c1a158c1e2ca21ce0c2718fa11e96e70e99fd4de" - [[package]] name = "indexmap" version = "2.7.0" @@ -1986,42 +1357,11 @@ dependencies = [ "hashbrown 0.15.2", ] -[[package]] -name = "indicatif" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" -dependencies = [ - "console", - "instant", - "number_prefix", - "portable-atomic", - "unicode-width", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "itertools" @@ -2043,38 +1383,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine 4.6.7", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.31" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" -dependencies = [ - "libc", -] +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" @@ -2086,21 +1397,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsonrpc-core" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" -dependencies = [ - "futures", - "futures-executor", - "futures-util", - "log", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "keccak" version = "0.1.5" @@ -2210,30 +1506,11 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -[[package]] -name = "lz4" -version = "1.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" -dependencies = [ - "lz4-sys", -] - -[[package]] -name = "lz4-sys" -version = "1.11.1+lz4-1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -2253,18 +1530,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "merlin" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.6.4", - "zeroize", -] - [[package]] name = "mime" version = "0.3.17" @@ -2272,139 +1537,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "mime_guess" -version = "2.0.5" +name = "miniz_oxide" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "mockall" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "lazy_static", - "mockall_derive", - "predicates", - "predicates-tree", -] - -[[package]] -name = "mockall_derive" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "modular-bitfield" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" -dependencies = [ - "modular-bitfield-impl", - "static_assertions", + "windows-sys 0.52.0", ] [[package]] -name = "modular-bitfield-impl" -version = "0.11.2" +name = "mollusk-svm" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +checksum = "1fceaf67fe3f95a9478f4f5b0d71e77c073eee7a795a74d6143317a22454c289" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "bincode", + "mollusk-svm-error", + "mollusk-svm-keys", + "solana-bpf-loader-program", + "solana-compute-budget", + "solana-logger", + "solana-program-runtime", + "solana-sdk", + "solana-system-program", + "solana-timings", ] [[package]] -name = "nix" -version = "0.29.0" +name = "mollusk-svm-error" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "8738bc85a52d123012209a573f17faffa1db440493396ae2e1f64fbb8f3579bf" dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", + "solana-sdk", + "thiserror 1.0.69", ] [[package]] -name = "no-std-compat" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" - -[[package]] -name = "nom" -version = "7.1.3" +name = "mollusk-svm-keys" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "d8a7656d86d743de0a9788ce4c0e9ff63028a42e350131ebe67c476cdde6ac9f" dependencies = [ - "memchr", - "minimal-lexical", + "mollusk-svm-error", + "solana-sdk", ] -[[package]] -name = "nonzero_ext" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" - -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - [[package]] name = "num" version = "0.2.1" @@ -2450,12 +1639,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-derive" version = "0.4.2" @@ -2478,9 +1661,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -2501,23 +1684,13 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - [[package]] name = "num_enum" version = "0.7.3" @@ -2533,41 +1706,26 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.90", ] -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - [[package]] name = "object" -version = "0.32.2" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] -[[package]] -name = "oid-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" -dependencies = [ - "asn1-rs", -] - [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -2575,90 +1733,11 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "openssl" -version = "0.10.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.4.1+3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "opentelemetry" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" -dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "js-sys", - "lazy_static", - "percent-encoding", - "pin-project", - "rand 0.8.5", - "thiserror 1.0.69", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2672,16 +1751,16 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -2692,15 +1771,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -2716,31 +1786,11 @@ dependencies = [ "num", ] -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2748,70 +1798,13 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "portable-atomic" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "predicates" -version = "2.1.5" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "difflib", - "float-cmp", - "itertools 0.10.5", - "normalize-line-endings", - "predicates-core", - "regex", -] - -[[package]] -name = "predicates-core" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" - -[[package]] -name = "predicates-tree" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" -dependencies = [ - "predicates-core", - "termtree", + "zerocopy", ] [[package]] @@ -2825,37 +1818,13 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.92" @@ -2895,122 +1864,43 @@ dependencies = [ ] [[package]] -name = "qualifier_attr" -version = "0.2.2" +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", - "quote", - "syn 2.0.90", ] [[package]] -name = "quanta" -version = "0.12.4" +name = "rand" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773ce68d0bb9bc7ef20be3536ffe94e223e1f365bd374108b2659fac0c65cfe6" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "crossbeam-utils", + "getrandom 0.1.16", "libc", - "once_cell", - "raw-cpuid", - "wasi 0.11.0+wasi-snapshot-preview1", - "web-sys", - "winapi", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", ] [[package]] -name = "quick-error" -version = "1.2.3" +name = "rand" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quinn" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" -dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls 0.23.20", - "socket2", - "thiserror 2.0.7", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" -dependencies = [ - "bytes", - "getrandom 0.2.14", - "rand 0.8.5", - "ring", - "rustc-hash", - "rustls 0.23.20", - "rustls-pki-types", - "rustls-platform-verifier", - "slab", - "thiserror 2.0.7", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] [[package]] name = "rand_chacha" @@ -3047,7 +1937,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", ] [[package]] @@ -3068,58 +1958,11 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "rand_xoshiro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" -dependencies = [ - "rand_core 0.6.4", -] - -[[package]] -name = "raw-cpuid" -version = "11.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -3174,12 +2017,11 @@ dependencies = [ "js-sys", "log", "mime", - "mime_guess", "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", @@ -3187,31 +2029,16 @@ dependencies = [ "system-configuration", "tokio", "tokio-rustls", - "tokio-util 0.7.10", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.4", + "webpki-roots", "winreg", ] -[[package]] -name = "reqwest-middleware" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" -dependencies = [ - "anyhow", - "async-trait", - "http", - "reqwest", - "serde", - "task-local-extensions", - "thiserror 1.0.69", -] - [[package]] name = "ring" version = "0.17.8" @@ -3220,7 +2047,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.14", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -3229,34 +2056,19 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc-hash" -version = "2.1.0" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] -[[package]] -name = "rusticata-macros" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" -dependencies = [ - "nom", -] - [[package]] name = "rustix" version = "0.38.42" @@ -3267,7 +2079,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3278,37 +2090,10 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki 0.101.7", + "rustls-webpki", "sct", ] -[[package]] -name = "rustls" -version = "0.23.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki 0.102.8", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe", - "rustls-pemfile 2.2.0", - "rustls-pki-types", - "schannel", - "security-framework", -] - [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -3318,51 +2103,6 @@ dependencies = [ "base64 0.21.7", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" -dependencies = [ - "web-time", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c7dc240fec5517e6c4eab3310438636cfe6391dfc345ba013109909a90d136" -dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls 0.23.20", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki 0.102.8", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - [[package]] name = "rustls-webpki" version = "0.101.7" @@ -3373,23 +2113,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" - [[package]] name = "rusty-fork" version = "0.3.0" @@ -3404,18 +2127,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scc" @@ -3426,15 +2140,6 @@ dependencies = [ "sdd", ] -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -3463,45 +2168,12 @@ version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9" -[[package]] -name = "security-framework" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "num-bigint 0.4.6", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" -[[package]] -name = "seqlock" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" -dependencies = [ - "parking_lot", -] - [[package]] name = "serde" version = "1.0.216" @@ -3603,17 +2275,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.9.9" @@ -3648,30 +2309,12 @@ dependencies = [ "keccak", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - [[package]] name = "signature" version = "1.6.4" @@ -3684,16 +2327,6 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" -[[package]] -name = "sized-chunks" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" -dependencies = [ - "bitmaps", - "typenum", -] - [[package]] name = "slab" version = "0.4.9" @@ -3711,9 +2344,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3721,9 +2354,9 @@ dependencies = [ [[package]] name = "solana-account" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b4e43476f7e13b6a8f571008cc6aff6ff0cae6e9c71ca96e6feb787e3409fd" +checksum = "730219420b206253977b8cc8fd7846ffe021ab2e2c718e70db420efbd2775547" dependencies = [ "bincode", "serde", @@ -3734,52 +2367,10 @@ dependencies = [ ] [[package]] -name = "solana-account-decoder" -version = "2.1.6" +name = "solana-account-info" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c195abdb9665bb390eda3972b750d04f87a5b023cfde6674a61b03452de15585" -dependencies = [ - "Inflector", - "base64 0.22.1", - "bincode", - "bs58", - "bv", - "lazy_static", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder-client-types", - "solana-config-program", - "solana-sdk", - "spl-token 6.0.0", - "spl-token-2022", - "spl-token-group-interface", - "spl-token-metadata-interface", - "thiserror 1.0.69", - "zstd", -] - -[[package]] -name = "solana-account-decoder-client-types" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b743d836d14dea475cc0a82a3f31316563888af97d06f5575a90f8ceb859f2" -dependencies = [ - "base64 0.22.1", - "bs58", - "serde", - "serde_derive", - "serde_json", - "solana-account", - "solana-pubkey", - "zstd", -] - -[[package]] -name = "solana-account-info" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42051fa2def3a2d9123f0e33b62a983b25c13d153a30e707b14d3c3b79a91592" +checksum = "6abe81cfc4a75f71a510c6856b03a7d8525e416af3c69d55daef62e6078b8d40" dependencies = [ "bincode", "serde", @@ -3788,135 +2379,20 @@ dependencies = [ "solana-pubkey", ] -[[package]] -name = "solana-accounts-db" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06cd13cf8d4db51dd1bb94c6b6a7ca5a1f4f26ddd1c5f708d9631838790d1931" -dependencies = [ - "ahash", - "bincode", - "blake3", - "bv", - "bytemuck", - "bytemuck_derive", - "bzip2", - "crossbeam-channel", - "dashmap", - "index_list", - "indexmap", - "itertools 0.12.1", - "lazy_static", - "log", - "lz4", - "memmap2", - "modular-bitfield", - "num_cpus", - "num_enum", - "rand 0.8.5", - "rayon", - "seqlock", - "serde", - "serde_derive", - "smallvec", - "solana-bucket-map", - "solana-inline-spl", - "solana-lattice-hash", - "solana-measure", - "solana-metrics", - "solana-nohash-hasher", - "solana-rayon-threadlimit", - "solana-sdk", - "solana-svm-transaction", - "static_assertions", - "tar", - "tempfile", - "thiserror 1.0.69", -] - -[[package]] -name = "solana-address-lookup-table-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1ecf05f94decc544055d61a2071a4dddd590d29c945061cf9abeac662020ec7" -dependencies = [ - "bincode", - "bytemuck", - "log", - "num-derive", - "num-traits", - "solana-feature-set", - "solana-log-collector", - "solana-program", - "solana-program-runtime", - "solana-sdk", - "thiserror 1.0.69", -] - [[package]] name = "solana-atomic-u64" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10dad9cf8527bbf74d3668505f563bd362e2e14d0fc77338d20973e881bbad0b" +checksum = "391b795afcdcad39ddc6c938d64b789d036cdfe00d9dc5ff83024cf2da9f066f" dependencies = [ "parking_lot", ] -[[package]] -name = "solana-banks-client" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad332be8ddaadb313b811853c21ff373a821c5e7a52a3e0757aabef4570b9d1" -dependencies = [ - "borsh 1.5.3", - "futures", - "solana-banks-interface", - "solana-program", - "solana-sdk", - "tarpc", - "thiserror 1.0.69", - "tokio", - "tokio-serde", -] - -[[package]] -name = "solana-banks-interface" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f1ba996f5b9214865dfe561d113f2cec114910ab82097035918aab228c0ede" -dependencies = [ - "serde", - "serde_derive", - "solana-sdk", - "tarpc", -] - -[[package]] -name = "solana-banks-server" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e3c78eb17b9af871f34c213115cfc1b0fe5125686a0a21171d62ea7ac44b96" -dependencies = [ - "bincode", - "crossbeam-channel", - "futures", - "solana-banks-interface", - "solana-client", - "solana-feature-set", - "solana-runtime", - "solana-sdk", - "solana-send-transaction-service", - "solana-svm", - "tarpc", - "tokio", - "tokio-serde", -] - [[package]] name = "solana-bincode" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e3b178d3783809a2480c542cd7c57c06e1bab2c0f21562fcb8cd13eabd0138e" +checksum = "9e85cb5961c356345a61378163fd9057011b35540f8bcdd8d8a09cb10117264f" dependencies = [ "bincode", "serde", @@ -3925,9 +2401,9 @@ dependencies = [ [[package]] name = "solana-bn254" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8f9c849dac8e6ef87c3c8035886df648ef5ec4c6d9d45b96fc045477e23a9b0" +checksum = "c39c4030db26ad618f7e18fb5284df19fd52a68e092a1ca58db857108c4cc777" dependencies = [ "ark-bn254", "ark-ec", @@ -3940,19 +2416,19 @@ dependencies = [ [[package]] name = "solana-borsh" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870197ea4929500d8e6f624c3eb578912b5063bbd5c8bfbe87396cd5b4257465" +checksum = "a5d526f3525ab22a3ada3f9a1d642664dafac00dc9208326b701a2045514eb04" dependencies = [ - "borsh 0.10.3", + "borsh 0.10.4", "borsh 1.5.3", ] [[package]] name = "solana-bpf-loader-program" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a529f5e85392e5c628f188a4b5f40e90d25bf303380b04c4f6272412a0501c0" +checksum = "142e0407f8428a1d2a33154d1d3d1c134ad257651ddff0811c17a6ee840def36" dependencies = [ "bincode", "byteorder", @@ -3975,169 +2451,31 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "solana-bucket-map" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeecd14db2155d6576ad5694bbc27e201b0a08c018e5e15c6d5be4893b503a14" -dependencies = [ - "bv", - "bytemuck", - "bytemuck_derive", - "log", - "memmap2", - "modular-bitfield", - "num_enum", - "rand 0.8.5", - "solana-measure", - "solana-sdk", - "tempfile", -] - -[[package]] -name = "solana-builtins-default-costs" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3327ae9cd1e31aed84f2c34ed17b7a940d2ca1fcc1ab414f551833a51d6cbf3a" -dependencies = [ - "ahash", - "lazy_static", - "log", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-compute-budget-program", - "solana-config-program", - "solana-loader-v4-program", - "solana-sdk", - "solana-stake-program", - "solana-system-program", - "solana-vote-program", -] - -[[package]] -name = "solana-client" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1502052be06ff6bfc86363955c2bf06e5f9640689fdb5900e5aa7d5b22633a9d" -dependencies = [ - "async-trait", - "bincode", - "dashmap", - "futures", - "futures-util", - "indexmap", - "indicatif", - "log", - "quinn", - "rayon", - "solana-connection-cache", - "solana-measure", - "solana-pubsub-client", - "solana-quic-client", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-rpc-client-nonce-utils", - "solana-sdk", - "solana-streamer", - "solana-thin-client", - "solana-tpu-client", - "solana-udp-client", - "thiserror 1.0.69", - "tokio", -] - [[package]] name = "solana-clock" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b26a68f89972fddb370ba33a49340bd3419da529893d9ee851211588aee811fa" +checksum = "7848171e53fa528efd41dd4b3ab919f47b851f8bb4a827d63ff95678f08737fc" dependencies = [ "serde", "serde_derive", "solana-sdk-macro", - "solana-sysvar-id", ] [[package]] name = "solana-compute-budget" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3366dd8be1d12ea197392cdc261ea1630d156b5685647ed7769959ef473f8aae" -dependencies = [ - "solana-sdk", -] - -[[package]] -name = "solana-compute-budget-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "700e90029b4aa3907bef8f5964451a5495cfc25a89374d0e94b7887b780ca587" -dependencies = [ - "solana-program-runtime", - "solana-sdk", -] - -[[package]] -name = "solana-config-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b94dd5229242839bf71572d903a38f2ea40db5ad408eca57015bcaaf2a7607" -dependencies = [ - "bincode", - "chrono", - "serde", - "serde_derive", - "solana-log-collector", - "solana-program-runtime", - "solana-sdk", - "solana-short-vec", -] - -[[package]] -name = "solana-connection-cache" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1445dd6a6d47b7a025af9f9c44ecb333716a5a6859f77f8da210d86bb89a7627" -dependencies = [ - "async-trait", - "bincode", - "crossbeam-channel", - "futures-util", - "indexmap", - "log", - "rand 0.8.5", - "rayon", - "solana-measure", - "solana-metrics", - "solana-sdk", - "thiserror 1.0.69", - "tokio", -] - -[[package]] -name = "solana-cost-model" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21f05cbc354339b05f7ceb9e3ee8ac95ef1abdf260383d57b93f6a06cd06805e" +checksum = "ebf2f023f471bd1195b7f420e13ffc2422592dd48e71104b4901300b49ac493e" dependencies = [ - "ahash", - "lazy_static", - "log", - "solana-builtins-default-costs", - "solana-compute-budget", - "solana-feature-set", - "solana-metrics", - "solana-runtime-transaction", "solana-sdk", - "solana-svm-transaction", - "solana-vote-program", ] [[package]] name = "solana-cpi" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3b62e1ca838f92b90c25ab68c297272cee8e2256dad18806a219b05cfcd247" +checksum = "25c536ad0ce25d84a64f48dedcb773e764827e0ef781eda41fa1fa35f5d64b38" dependencies = [ "solana-account-info", "solana-define-syscall", @@ -4149,9 +2487,9 @@ dependencies = [ [[package]] name = "solana-curve25519" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ce85c03e05856b4094891fbaedf9ea9b0334b19d8fba72bd4b106442b46e12" +checksum = "f934d38b6f2a940fb1e1d8eaa17a14ffd3773b37be9fb29fa4bcec1bac5e4591" dependencies = [ "bytemuck", "bytemuck_derive", @@ -4162,24 +2500,24 @@ dependencies = [ [[package]] name = "solana-decode-error" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1323dbdb7c8ca717bcd7987a3f45619b5b6517dc3ee22a21342122a5516125c3" +checksum = "c5a431f532d030098e81d120877f2dddbd3dd90bea5b259198a6aae4ff6456c3" dependencies = [ "num-traits", ] [[package]] name = "solana-define-syscall" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23cf0144176f94019a27ce46372661f67007232eea16cae96cb985fc25131d5" +checksum = "7062ae1de58e294d3bee5fd2c89efc155b7f7383ddce4cb88345dfafaaabc5bd" [[package]] name = "solana-derivation-path" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ccae348499724f35dd03f395b415c54ab3929799c90df0d33e9878947e0987" +checksum = "12080d9bf8eecd559c6f40b5aaf9e47f7f28f515218087f83f02e493b46d8388" dependencies = [ "derivation-path", "qstring", @@ -4188,21 +2526,20 @@ dependencies = [ [[package]] name = "solana-epoch-schedule" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c60dde3613fcd1af91c2033e67ffe8c8d2bcd58085c53c842fa7903fa839ad38" +checksum = "65c4cf7d7c266d353169cf4feeada5e4bba3a55f33715535fa1ef49080eac3e0" dependencies = [ "serde", "serde_derive", "solana-sdk-macro", - "solana-sysvar-id", ] [[package]] name = "solana-feature-set" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c225a8a8be02a514d4180e6a7c6ff68e193c8e722ac14cde565fe68b671a4a" +checksum = "5cebf45992982065a0b01b4e109bf039b2ebf6394b21672382fd951516d4c9b0" dependencies = [ "lazy_static", "solana-clock", @@ -4212,21 +2549,11 @@ dependencies = [ "solana-sha256-hasher", ] -[[package]] -name = "solana-fee" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b87b940cad820c4ae7af3fed8598e35c042adade5b91dee51218015bb5f906" -dependencies = [ - "solana-sdk", - "solana-svm-transaction", -] - [[package]] name = "solana-fee-calculator" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c706f3d151d0abc197ca2fcecf877ace03d613be6fae766de12f5fb41c96b04" +checksum = "c2befe056ece2eb5807298c2b569a35ee52f79df859bdd16a1f97869f8224a28" dependencies = [ "log", "serde", @@ -4235,9 +2562,9 @@ dependencies = [ [[package]] name = "solana-hash" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86aabbd7ebf807689a0355f053d6dc31d2131c2d83613011a374a18cc5d61b7" +checksum = "1807bc4e9e1d25271514167d5a1e698ce5a330bce547a368242dd63b355b5faa" dependencies = [ "borsh 1.5.3", "bs58", @@ -4253,33 +2580,23 @@ dependencies = [ [[package]] name = "solana-inflation" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6954cd9fb4cd351e9e01d3fda020936f7cb44eb9efab3baecc3a5de1c9de8c1a" +checksum = "a60b572cdf0ec8fcf5a53e5ba4e3e19814dd96c2b9c156d5828be68d0d2e7103" dependencies = [ "serde", "serde_derive", ] -[[package]] -name = "solana-inline-spl" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f116f35b0b8ec99abf0e0cda7064eb3dfb6d16e8bc8767c116f91c256db9b859" -dependencies = [ - "bytemuck", - "solana-pubkey", -] - [[package]] name = "solana-instruction" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed5710c998efd09ffb596cf5e7266c11cd56e3a136c8a1f940e8525fd5be6e" +checksum = "bfef689e06e5c7cb6206d4dc61ac77733de4f72d754e0d531393206abc27dbe4" dependencies = [ "bincode", "borsh 1.5.3", - "getrandom 0.2.14", + "getrandom 0.2.15", "js-sys", "num-traits", "serde", @@ -4291,59 +2608,29 @@ dependencies = [ [[package]] name = "solana-last-restart-slot" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5647af0980c796c942e33f1f7dbffca29b7747630b720e6975abb1d7c531f6" +checksum = "b3186feae497bdfd2e77bfa56caed38b1cb1b0f389506666e3331f0b9ae799cb" dependencies = [ "serde", "serde_derive", "solana-sdk-macro", - "solana-sysvar-id", ] [[package]] -name = "solana-lattice-hash" -version = "2.1.6" +name = "solana-log-collector" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cb58f78f4c7424344cca3fffa3210f5c10bae9b57639a5bc43b2111e8551160" +checksum = "b529f5736a6c0794a885dac2e091138d3db6d924335906f117a62b58b0d3b5dc" dependencies = [ - "base64 0.22.1", - "blake3", - "bs58", - "bytemuck", + "log", ] [[package]] -name = "solana-loader-v4-program" +name = "solana-logger" version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d281df3057ee55a83081b399947fcbf50b5a1726c64b1d86bae291fe16db08" -dependencies = [ - "log", - "solana-bpf-loader-program", - "solana-compute-budget", - "solana-log-collector", - "solana-measure", - "solana-program-runtime", - "solana-sdk", - "solana-type-overrides", - "solana_rbpf", -] - -[[package]] -name = "solana-log-collector" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636132217fc00b32a72a3fff2dfdda5a377291edc788d3286a3fbf73caaf89cf" -dependencies = [ - "log", -] - -[[package]] -name = "solana-logger" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037e89416c5f3e160841a3717241f86e5a3e1b3edf4d946e976b4960c11e1073" +checksum = "037e89416c5f3e160841a3717241f86e5a3e1b3edf4d946e976b4960c11e1073" dependencies = [ "env_logger", "lazy_static", @@ -4352,15 +2639,15 @@ dependencies = [ [[package]] name = "solana-measure" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc2470b663cde7fcd3dc644fdcb19181cf5d87ece8cab270e182ff33b48b357" +checksum = "33b2047a2f588082b71080b060918f107c3330ae1505f759c3b2d74bae9d9c88" [[package]] name = "solana-metrics" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc3248d11553718544485736382dd9a8b619f42f39fba41b9211638d35414bbc" +checksum = "6319c74238e8ed4f7159fd37c693a574ab8316d03b053103f9cc83dce13f1d5c" dependencies = [ "crossbeam-channel", "gethostname", @@ -4373,49 +2660,24 @@ dependencies = [ [[package]] name = "solana-msg" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d6a46fcbbaa38193b5b6aeec531395da8dac8dcd183ac6d80d94e6513fc4ad8" +checksum = "1f7551f85064bc7299d56dbd7126258b084a2d78d0325b1579324f818b405123" dependencies = [ "solana-define-syscall", ] [[package]] name = "solana-native-token" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa3c5006bbea99b810ad8fc6ae168fc83891b607a13a9aa6be39db71a700f87" - -[[package]] -name = "solana-net-utils" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521d93b4023bfce59bff12f7821ab6803ddfdf8d6ead19e8bbdeaee84a609a18" -dependencies = [ - "bincode", - "crossbeam-channel", - "log", - "nix", - "rand 0.8.5", - "serde", - "serde_derive", - "socket2", - "solana-sdk", - "tokio", - "url", -] - -[[package]] -name = "solana-nohash-hasher" -version = "0.2.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" +checksum = "5d0c4074f5fc67574dabd8f30fe6e51e290a812d88326b19b49c462058e23340" [[package]] name = "solana-packet" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05fd58e2633824294a4eb1159e3f2cd9fed8d8c4d25fb4e3388f872c314e5ffd" +checksum = "0dafc2d84e57dbfe32583fe915962bd2ca3af6be496628a871db3c3d697b38d7" dependencies = [ "bincode", "bitflags 2.6.0", @@ -4425,38 +2687,11 @@ dependencies = [ "serde_with", ] -[[package]] -name = "solana-perf" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adbb524303dd629a59dc08352da0d232f54172c5454948749966b370eac3ea2a" -dependencies = [ - "ahash", - "bincode", - "bv", - "caps", - "curve25519-dalek 4.1.3", - "dlopen2", - "fnv", - "lazy_static", - "libc", - "log", - "nix", - "rand 0.8.5", - "rayon", - "serde", - "solana-metrics", - "solana-rayon-threadlimit", - "solana-sdk", - "solana-short-vec", - "solana-vote-program", -] - [[package]] name = "solana-poseidon" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789063a1bc183d95d5a62787c7d85fe1d0dc1f08f2282a7124dc5e913221ae3b" +checksum = "f193a65f0db7fe5615c76c2814d6450a2e4cda61f786d5bf7a6b1ad0c179b947" dependencies = [ "ark-bn254", "light-poseidon", @@ -4466,9 +2701,9 @@ dependencies = [ [[package]] name = "solana-precompile-error" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e289d47a9c60b9636d86458e050eca1a74f7c932abeee3bca2a0c256b8c9814e" +checksum = "a30ab58b9e37cde4e5577282670f30df71b97b6b06dbdb420e9b84e57b831227" dependencies = [ "num-traits", "solana-decode-error", @@ -4476,15 +2711,15 @@ dependencies = [ [[package]] name = "solana-program" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afc847b91b77c48113a55f7f492cc7e982e1778c6b954a05feb499f9b8c3cc4" +checksum = "9040decf2f295d35da22557eeab3768ab8dfca8aed9afe668663c8fa0e97d60e" dependencies = [ "base64 0.22.1", "bincode", "bitflags 2.6.0", "blake3", - "borsh 0.10.3", + "borsh 0.10.4", "borsh 1.5.3", "bs58", "bv", @@ -4494,7 +2729,7 @@ dependencies = [ "console_log", "curve25519-dalek 4.1.3", "five8_const", - "getrandom 0.2.14", + "getrandom 0.2.15", "js-sys", "lazy_static", "log", @@ -4541,7 +2776,6 @@ dependencies = [ "solana-slot-hashes", "solana-slot-history", "solana-stable-layout", - "solana-sysvar-id", "solana-transaction-error", "thiserror 1.0.69", "wasm-bindgen", @@ -4549,9 +2783,9 @@ dependencies = [ [[package]] name = "solana-program-entrypoint" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "988a49fb8231e95861d11b40931f49e06f0dea5a29241acf7cbca644c52abd6b" +checksum = "0eb90f3fa3e979b912451a404508f1f90bb6e5c1d7767625f622b20016fb9fde" dependencies = [ "solana-account-info", "solana-msg", @@ -4561,9 +2795,9 @@ dependencies = [ [[package]] name = "solana-program-error" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2473773ee9cebf6ba3d7d1fe911938bc2a3a694e85bea33fd7a99d397cde1202" +checksum = "dd089caeef26dd07bd12b7b67d45e92faddc2fc67a960f316df7ae4776a2f3d5" dependencies = [ "borsh 1.5.3", "num-traits", @@ -4577,9 +2811,9 @@ dependencies = [ [[package]] name = "solana-program-memory" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d9e6ca90bbc3020b7b37091c05049f5de48e397545093ec303dc6eff3d4720c" +checksum = "ed4bc044dc2b49c323aeff04aec03c908a052e278c2edf2f7616f32fc0f1bcd9" dependencies = [ "num-traits", "solana-define-syscall", @@ -4587,24 +2821,24 @@ dependencies = [ [[package]] name = "solana-program-option" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2334c5f9adcc25c6390fbf87ac127adbfbd8943465726e5f389159677ceba2" +checksum = "3babbdffd81994c043fc9a61458ce87496218825d6e9a303de643c0a53089b9a" [[package]] name = "solana-program-pack" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305475eef9404539cce0c561ab9997b875cc5509f7c553859cd059fdf93b0ab2" +checksum = "b8fb28439d23e1f505e59c7a14ed5012365ab7aa0f20dc7bda048e02ff231cf6" dependencies = [ "solana-program-error", ] [[package]] name = "solana-program-runtime" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05abf5a66475f23769700597129cce9f76cfaacb45babf83ffec3157da8c7ce4" +checksum = "ba1de51df173401d50c0f4cf750f5070d7a4c82125a03c1aec9622dc041b0b54" dependencies = [ "base64 0.22.1", "bincode", @@ -4630,56 +2864,20 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "solana-program-test" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f12ddc1b98a4af13a4c0ff9b67ae5a4a58c79fcb7602501fcb6679d1e9d783b" -dependencies = [ - "assert_matches", - "async-trait", - "base64 0.22.1", - "bincode", - "chrono-humanize", - "crossbeam-channel", - "log", - "serde", - "solana-accounts-db", - "solana-banks-client", - "solana-banks-interface", - "solana-banks-server", - "solana-bpf-loader-program", - "solana-compute-budget", - "solana-feature-set", - "solana-inline-spl", - "solana-instruction", - "solana-log-collector", - "solana-logger", - "solana-program-runtime", - "solana-runtime", - "solana-sdk", - "solana-svm", - "solana-timings", - "solana-vote-program", - "solana_rbpf", - "thiserror 1.0.69", - "tokio", -] - [[package]] name = "solana-pubkey" -version = "2.1.6" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a954fba3af498201179981818b0ed61f95c32b4a3db5ea9cc042c971c84cdeae" +checksum = "bea3215775fcedf200d47590c7e2ce9a3a46bc2b7d3f77d0eae9c6edf0a39aec" dependencies = [ - "borsh 0.10.3", + "borsh 0.10.4", "borsh 1.5.3", "bs58", "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", "five8_const", - "getrandom 0.2.14", + "getrandom 0.2.15", "js-sys", "num-traits", "rand 0.8.5", @@ -4694,1044 +2892,282 @@ dependencies = [ ] [[package]] -name = "solana-pubsub-client" -version = "2.1.6" +name = "solana-rent" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f6f2c554cec02f87eca3e2461e1923db157d2d615e919fc2b93807465cbe6a" +checksum = "aab3f4a270196c38d62c3bb3c7a2f07732af2c772b50da49c9b1e2c9d2ace286" dependencies = [ - "crossbeam-channel", - "futures-util", - "log", - "reqwest", - "semver", "serde", "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-rpc-client-api", - "solana-sdk", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tungstenite", - "url", + "solana-sdk-macro", ] [[package]] -name = "solana-quic-client" -version = "2.1.6" +name = "solana-sanitize" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "203b90994371db8cade8e885f74ec9f68ee02a32b25d514594158b2551a4e5ed" + +[[package]] +name = "solana-sdk" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c707a5c4aba604c06c0eeced102355229a7696ed4dc6a26c71bba5d74d86fc5" +checksum = "524604d94185c189616296e5b7da1014cc96d1e446bd2b26f247f00708b9225a" dependencies = [ - "async-lock", - "async-trait", - "futures", + "bincode", + "bitflags 2.6.0", + "borsh 1.5.3", + "bs58", + "bytemuck", + "bytemuck_derive", + "byteorder", + "chrono", + "digest 0.10.7", + "ed25519-dalek", + "ed25519-dalek-bip32", + "getrandom 0.1.16", + "hmac 0.12.1", "itertools 0.12.1", + "js-sys", "lazy_static", + "libsecp256k1", "log", - "quinn", - "quinn-proto", - "rustls 0.23.20", - "solana-connection-cache", - "solana-measure", - "solana-metrics", - "solana-net-utils", - "solana-rpc-client-api", - "solana-sdk", - "solana-streamer", + "memmap2", + "num-derive", + "num-traits", + "num_enum", + "pbkdf2", + "rand 0.7.3", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "serde_with", + "sha2 0.10.8", + "sha3", + "siphasher", + "solana-account", + "solana-bn254", + "solana-decode-error", + "solana-derivation-path", + "solana-feature-set", + "solana-inflation", + "solana-instruction", + "solana-native-token", + "solana-packet", + "solana-precompile-error", + "solana-program", + "solana-program-memory", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-macro", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-short-vec", + "solana-signature", + "solana-transaction-error", "thiserror 1.0.69", - "tokio", + "wasm-bindgen", ] [[package]] -name = "solana-rayon-threadlimit" -version = "2.1.6" +name = "solana-sdk-macro" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eeb2db0e5055cc45bbb9b6f8e4bc879b49dadf5734397a749c4b7da9193e71e" +checksum = "1bd2265b93dce9d3dcf9f395abf1a85b5e06e4da4aa60ca147620003ac3abc67" dependencies = [ - "lazy_static", - "num_cpus", + "bs58", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] -name = "solana-rent" -version = "2.1.6" +name = "solana-secp256k1-recover" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebcc59bff8b3c773214545d038b718a3e2e63c920b8172f85725463029f7f00" +checksum = "f2eef5a00a75648273c3fb6e3d85b0c8c02fcc1e36c4271664dcc39b6b128d41" dependencies = [ - "serde", - "serde_derive", - "solana-sdk-macro", - "solana-sysvar-id", + "borsh 1.5.3", + "libsecp256k1", + "solana-define-syscall", + "thiserror 1.0.69", ] [[package]] -name = "solana-rpc-client" -version = "2.1.6" +name = "solana-serde-varint" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85883f214cff98a97432646ace94eea3cfe309b068841c0feae93d0a1e7b238" +checksum = "9aeb51d3c20e2a61db0ef72617f3b8c9207a342a867af454a95f17add9f6c262" dependencies = [ - "async-trait", - "base64 0.22.1", - "bincode", - "bs58", - "indicatif", - "log", - "reqwest", - "reqwest-middleware", - "semver", "serde", - "serde_derive", - "serde_json", - "solana-account-decoder-client-types", - "solana-rpc-client-api", - "solana-sdk", - "solana-transaction-status-client-types", - "solana-version", - "solana-vote-program", - "tokio", ] [[package]] -name = "solana-rpc-client-api" -version = "2.1.6" +name = "solana-serialize-utils" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791168d04387734755d3a7e81f5228cb305041c09bf4fbfc0823c8380acdf3e7" +checksum = "0cfb0b57c6a431fb15ff33053caadb6c36aed4e1ce74bea9adfc459a710b3626" dependencies = [ - "anyhow", - "base64 0.22.1", - "bs58", - "jsonrpc-core", - "reqwest", - "reqwest-middleware", - "semver", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder-client-types", - "solana-inline-spl", - "solana-sdk", - "solana-transaction-status-client-types", - "solana-version", - "thiserror 1.0.69", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", ] [[package]] -name = "solana-rpc-client-nonce-utils" -version = "2.1.6" +name = "solana-sha256-hasher" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e515480bef7a3476cee636a69aa237e2e8ba73f82ba95d6e307397144ce4fc" +checksum = "bd115f3a1136314b0183235080d29023530c3a0a5df60505fdb7ea620eff9fd6" dependencies = [ - "solana-rpc-client", - "solana-sdk", - "thiserror 1.0.69", + "sha2 0.10.8", + "solana-define-syscall", + "solana-hash", ] [[package]] -name = "solana-runtime" -version = "2.1.6" +name = "solana-short-vec" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297794ae50b36180a7c769c864b83cbfb91ea438019ea15bcff66e21f6b7e048" +checksum = "08e55330b694db1139dcdf2a1ea7781abe8bd994dec2ab29e36abfd06e4e9274" dependencies = [ - "ahash", - "aquamarine", - "arrayref", - "base64 0.22.1", - "bincode", - "blake3", - "bv", - "bytemuck", - "byteorder", - "bzip2", - "crossbeam-channel", - "dashmap", - "dir-diff", - "flate2", - "fnv", - "im", - "index_list", - "itertools 0.12.1", - "lazy_static", - "libc", - "log", - "lz4", - "memmap2", - "mockall", - "modular-bitfield", - "num-derive", - "num-traits", - "num_cpus", - "num_enum", - "percentage", - "qualifier_attr", - "rand 0.8.5", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "serde_with", - "solana-accounts-db", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-bucket-map", - "solana-compute-budget", - "solana-compute-budget-program", - "solana-config-program", - "solana-cost-model", - "solana-feature-set", - "solana-fee", - "solana-inline-spl", - "solana-lattice-hash", - "solana-loader-v4-program", - "solana-measure", - "solana-metrics", - "solana-perf", - "solana-program", - "solana-program-runtime", - "solana-rayon-threadlimit", - "solana-runtime-transaction", - "solana-sdk", - "solana-stake-program", - "solana-svm", - "solana-svm-rent-collector", - "solana-svm-transaction", - "solana-system-program", - "solana-timings", - "solana-transaction-status", - "solana-version", - "solana-vote", - "solana-vote-program", - "solana-zk-elgamal-proof-program", - "solana-zk-sdk", - "solana-zk-token-proof-program", - "solana-zk-token-sdk", - "static_assertions", - "strum", - "strum_macros", - "symlink", - "tar", - "tempfile", - "thiserror 1.0.69", - "zstd", -] - -[[package]] -name = "solana-runtime-transaction" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df2638adfc8975cb111bc2ab3ee2cb04572ecbc96d1b414f1c9838729dc0c54" -dependencies = [ - "agave-transaction-view", - "log", - "solana-builtins-default-costs", - "solana-compute-budget", - "solana-pubkey", - "solana-sdk", - "solana-svm-transaction", - "thiserror 1.0.69", -] - -[[package]] -name = "solana-sanitize" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05ecd7ec442abf0561cbf06984484d6368e71a4882213bfa68b658b0f8d6a0e" - -[[package]] -name = "solana-sdk" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216fa7d6ef4d741ec21e0054e78d86c5da0c2033f377b03de5eb65d264d8df13" -dependencies = [ - "bincode", - "bitflags 2.6.0", - "borsh 1.5.3", - "bs58", - "bytemuck", - "bytemuck_derive", - "byteorder", - "chrono", - "digest 0.10.7", - "ed25519-dalek", - "ed25519-dalek-bip32", - "getrandom 0.1.16", - "hmac 0.12.1", - "itertools 0.12.1", - "js-sys", - "lazy_static", - "libsecp256k1", - "log", - "memmap2", - "num-derive", - "num-traits", - "num_enum", - "pbkdf2", - "rand 0.7.3", - "rand 0.8.5", - "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "serde_with", - "sha2 0.10.8", - "sha3", - "siphasher", - "solana-account", - "solana-bn254", - "solana-decode-error", - "solana-derivation-path", - "solana-feature-set", - "solana-inflation", - "solana-instruction", - "solana-native-token", - "solana-packet", - "solana-precompile-error", - "solana-program", - "solana-program-memory", - "solana-pubkey", - "solana-sanitize", - "solana-sdk-macro", - "solana-secp256k1-recover", - "solana-secp256r1-program", - "solana-serde-varint", - "solana-short-vec", - "solana-signature", - "solana-transaction-error", - "thiserror 1.0.69", - "wasm-bindgen", -] - -[[package]] -name = "solana-sdk-macro" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85df4723291cfec8ffe9dadc59d565afcae12ea9a6460b7b28c4da21c2c4a887" -dependencies = [ - "bs58", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "solana-secp256k1-recover" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c38fc7bc33f78af99c4848c9a924b2b6e5d33d96f269d108777d982de72f73" -dependencies = [ - "borsh 1.5.3", - "libsecp256k1", - "solana-define-syscall", - "thiserror 1.0.69", -] - -[[package]] -name = "solana-secp256r1-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5bbc17379248923203317b337ce871bbf1ba6c59f01c49dc65895ffdc684f0a" -dependencies = [ - "bytemuck", - "openssl", - "solana-feature-set", - "solana-instruction", - "solana-precompile-error", - "solana-pubkey", -] - -[[package]] -name = "solana-security-txt" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" - -[[package]] -name = "solana-send-transaction-service" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f09eea5dbb0f2489799f337caf51243bc8d1a9277a90d8a1bf7c170ad86595" -dependencies = [ - "crossbeam-channel", - "log", - "solana-client", - "solana-connection-cache", - "solana-measure", - "solana-metrics", - "solana-runtime", - "solana-sdk", - "solana-tpu-client", -] - -[[package]] -name = "solana-serde-varint" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e2fc696c10a2b02356584cbd45d83d42b01b10256cb36b5d0c3768e5adf9283" -dependencies = [ - "serde", -] - -[[package]] -name = "solana-serialize-utils" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b04c6fb71e4cdd10480bc8d306aca6d2a7494e6267e4f103085a89b2ec04e4c" -dependencies = [ - "solana-instruction", - "solana-pubkey", - "solana-sanitize", -] - -[[package]] -name = "solana-sha256-hasher" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4c977c6c4d95c8b43a9f405844f29a73c9d8b0a7c561b91d4f6a44f290d35c" -dependencies = [ - "sha2 0.10.8", - "solana-define-syscall", - "solana-hash", -] - -[[package]] -name = "solana-short-vec" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ca5799b37642e4e273d7d848564739eab45df670edcc61b4696ef0d5ebe4a8c" -dependencies = [ - "serde", -] - -[[package]] -name = "solana-signature" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d28fe70f88bffb651a6ff8c37c236b935e97589865ca32e4a4544cdd10c7b268" -dependencies = [ - "bs58", - "ed25519-dalek", - "generic-array", - "rand 0.8.5", - "serde", - "serde_derive", - "solana-sanitize", -] - -[[package]] -name = "solana-slot-hashes" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e596d3719b4c03987de87c8cc25b34b6afcf7464c82b4d9c9b114304d882c97" -dependencies = [ - "serde", - "serde_derive", - "solana-hash", - "solana-sysvar-id", -] - -[[package]] -name = "solana-slot-history" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4022b0e8a7f043bd61504fff79176c02b52f69a69299023884b194a1405c0f05" -dependencies = [ - "bv", - "serde", - "serde_derive", - "solana-sysvar-id", -] - -[[package]] -name = "solana-stable-layout" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82f0665dfcfcb4433708abff54db5ee105fe1bb8db7fd409074bd0275582105" -dependencies = [ - "solana-instruction", - "solana-pubkey", -] - -[[package]] -name = "solana-stake-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d582421c0cffbf5174965c4a45aa05e90d584b6b13688ea1a13e9d332e3e4f25" -dependencies = [ - "bincode", - "log", - "solana-config-program", - "solana-feature-set", - "solana-log-collector", - "solana-program-runtime", - "solana-sdk", - "solana-type-overrides", - "solana-vote-program", -] - -[[package]] -name = "solana-streamer" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3173f4634b4e0acc366dec277744af50ffbf661dfe41291adf1406841a1b9c96" -dependencies = [ - "async-channel", - "bytes", - "crossbeam-channel", - "dashmap", - "futures", - "futures-util", - "governor", - "histogram", - "indexmap", - "itertools 0.12.1", - "libc", - "log", - "nix", - "pem", - "percentage", - "quinn", - "quinn-proto", - "rand 0.8.5", - "rustls 0.23.20", - "smallvec", - "socket2", - "solana-measure", - "solana-metrics", - "solana-perf", - "solana-sdk", - "solana-transaction-metrics-tracker", - "thiserror 1.0.69", - "tokio", - "tokio-util 0.7.10", - "x509-parser", -] - -[[package]] -name = "solana-svm" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bf9d2af384033d0eae21a55124858ced941856364316626cf974a94be14ae5" -dependencies = [ - "itertools 0.12.1", - "log", - "percentage", - "serde", - "serde_derive", - "solana-bpf-loader-program", - "solana-compute-budget", - "solana-feature-set", - "solana-fee", - "solana-loader-v4-program", - "solana-log-collector", - "solana-measure", - "solana-program-runtime", - "solana-runtime-transaction", - "solana-sdk", - "solana-svm-rent-collector", - "solana-svm-transaction", - "solana-system-program", - "solana-timings", - "solana-type-overrides", - "solana-vote", - "thiserror 1.0.69", -] - -[[package]] -name = "solana-svm-rent-collector" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "813e8669142396c7898ce9439d1ebfcfbf7f2edfc79f6fcaa35a87060a4af3ff" -dependencies = [ - "solana-sdk", -] - -[[package]] -name = "solana-svm-transaction" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572fbc0b6fa828a7bfd2c7b3039f61c169981974f37882ca4fac138290be9ce0" -dependencies = [ - "solana-sdk", -] - -[[package]] -name = "solana-system-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d271fdd4194fcc7de75c724c05f3d4a7062dba6ef279c7e8bfbd694ef7fb7ab" -dependencies = [ - "bincode", - "log", - "serde", - "serde_derive", - "solana-log-collector", - "solana-program-runtime", - "solana-sdk", - "solana-type-overrides", -] - -[[package]] -name = "solana-sysvar-id" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bbed7acdd711e0d620c9b7f788d041d35731c2c675d1d687498745d73826ca4" -dependencies = [ - "solana-pubkey", -] - -[[package]] -name = "solana-thin-client" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9facb2fbf83b8a3acb1cb4523bffa3db7be838faf2cfda374f0d99120917d870" -dependencies = [ - "bincode", - "log", - "rayon", - "solana-connection-cache", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-sdk", -] - -[[package]] -name = "solana-timings" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a83fbf8377e65d4c8e6a3c3c877c944a530ca9003f94389fd1528213c7c001" -dependencies = [ - "eager", - "enum-iterator", - "solana-sdk", -] - -[[package]] -name = "solana-tpu-client" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31cb5c39698855b236b6266025b2f31b1948ee370cd53a5cca6c7c62eea3104d" -dependencies = [ - "async-trait", - "bincode", - "futures-util", - "indexmap", - "indicatif", - "log", - "rayon", - "solana-connection-cache", - "solana-measure", - "solana-pubsub-client", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-sdk", - "thiserror 1.0.69", - "tokio", -] - -[[package]] -name = "solana-transaction-error" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae45f064c8e6006a426b31a1182123ec4daf8cca50bd7aea6e796e6205a7911e" -dependencies = [ - "serde", - "serde_derive", - "solana-instruction", - "solana-sanitize", -] - -[[package]] -name = "solana-transaction-metrics-tracker" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb406ed0db097a5d2067c3c737bec3f515ea70a2cfa5abec8fc0606098049e42" -dependencies = [ - "base64 0.22.1", - "bincode", - "lazy_static", - "log", - "rand 0.8.5", - "solana-perf", - "solana-sdk", - "solana-short-vec", -] - -[[package]] -name = "solana-transaction-status" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "254b3f1295b8654604d1f1b2980a4ec81621c071cc7bcbb8b3e6eb44ce98e8b1" -dependencies = [ - "Inflector", - "base64 0.22.1", - "bincode", - "borsh 1.5.3", - "bs58", - "lazy_static", - "log", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-sdk", - "solana-transaction-status-client-types", - "spl-associated-token-account", - "spl-memo", - "spl-token 6.0.0", - "spl-token-2022", - "spl-token-group-interface", - "spl-token-metadata-interface", - "thiserror 1.0.69", -] - -[[package]] -name = "solana-transaction-status-client-types" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a853cb1b1d5d1b521a51ae4666668f321505f0280839b00337d2620a9aba641" -dependencies = [ - "base64 0.22.1", - "bincode", - "bs58", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder-client-types", - "solana-sdk", - "solana-signature", - "thiserror 1.0.69", -] - -[[package]] -name = "solana-type-overrides" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4347abe10a8290cb6b135b1e40115e4d390d29588fb5ba598be891a98d09e10d" -dependencies = [ - "lazy_static", - "rand 0.8.5", -] - -[[package]] -name = "solana-udp-client" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b3064f000984b1f1032b3686577e452c423cbe3f8208efc713c16408f3a4086" -dependencies = [ - "async-trait", - "solana-connection-cache", - "solana-net-utils", - "solana-sdk", - "solana-streamer", - "thiserror 1.0.69", - "tokio", -] - -[[package]] -name = "solana-version" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b16c635fe2ccc3287bd5f84c6c86fbf316510df4229506d0bd9af50f2f1780" -dependencies = [ - "semver", - "serde", - "serde_derive", - "solana-feature-set", - "solana-sanitize", - "solana-serde-varint", -] - -[[package]] -name = "solana-vote" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228c93777a3ad6dc60abe422c558e8476ed0de4fe2b8784dfacb07951ca38355" -dependencies = [ - "itertools 0.12.1", - "log", - "serde", - "serde_derive", - "solana-sdk", - "thiserror 1.0.69", -] - -[[package]] -name = "solana-vote-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b556c4d1e742e8ab829bfa33b01cc22b823e7f42351e7ba24e4b2e26c3138f" -dependencies = [ - "bincode", - "log", - "num-derive", - "num-traits", - "serde", - "serde_derive", - "solana-feature-set", - "solana-metrics", - "solana-program", - "solana-program-runtime", - "solana-sdk", - "thiserror 1.0.69", -] - -[[package]] -name = "solana-zk-elgamal-proof-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c16a1e687c3f2f88785d8fb8e802dba2b46430f970cd61588fbd3a78371ef4" -dependencies = [ - "bytemuck", - "num-derive", - "num-traits", - "solana-log-collector", - "solana-program-runtime", - "solana-sdk", - "solana-zk-sdk", -] - -[[package]] -name = "solana-zk-sdk" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea58ce4bcac4c6f3577ffc753b8bff3d259169bde1827b4466acb5daae088d2" -dependencies = [ - "aes-gcm-siv", - "base64 0.22.1", - "bincode", - "bytemuck", - "bytemuck_derive", - "curve25519-dalek 4.1.3", - "itertools 0.12.1", - "js-sys", - "lazy_static", - "merlin", - "num-derive", - "num-traits", - "rand 0.8.5", - "serde", - "serde_derive", - "serde_json", - "sha3", - "solana-derivation-path", - "solana-program", - "solana-sdk", - "subtle", - "thiserror 1.0.69", - "wasm-bindgen", - "zeroize", -] - -[[package]] -name = "solana-zk-token-proof-program" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf2fd51bccc6be1173e4541f8a1390746e080d77165ee5fc40a9a390a82c55b" -dependencies = [ - "bytemuck", - "num-derive", - "num-traits", - "solana-feature-set", - "solana-log-collector", - "solana-program-runtime", - "solana-sdk", - "solana-zk-token-sdk", -] - -[[package]] -name = "solana-zk-token-sdk" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4340e5b7e4c3aa1d41ee638ab7d13eb1bcfc32d59c275a9f41838f059728aa6" -dependencies = [ - "aes-gcm-siv", - "base64 0.22.1", - "bincode", - "bytemuck", - "bytemuck_derive", - "byteorder", - "curve25519-dalek 4.1.3", - "itertools 0.12.1", - "lazy_static", - "merlin", - "num-derive", - "num-traits", - "rand 0.8.5", "serde", - "serde_derive", - "serde_json", - "sha3", - "solana-curve25519", - "solana-derivation-path", - "solana-program", - "solana-sdk", - "subtle", - "thiserror 1.0.69", - "zeroize", -] - -[[package]] -name = "solana_rbpf" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1941b5ef0c3ce8f2ac5dd984d0fb1a97423c4ff2a02eec81e3913f02e2ac2b" -dependencies = [ - "byteorder", - "combine 3.8.1", - "hash32", - "libc", - "log", - "rand 0.8.5", - "rustc-demangle", - "scroll", - "thiserror 1.0.69", - "winapi", ] [[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spinning_top" -version = "0.3.0" +name = "solana-signature" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +checksum = "3ad9784d110f195a3a4fe423479d18f05b01a1c380a1430644a3b3038fdbe2f0" dependencies = [ - "lock_api", + "bs58", + "ed25519-dalek", + "generic-array", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-sanitize", ] [[package]] -name = "spl-associated-token-account" -version = "4.0.0" +name = "solana-slot-hashes" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68034596cf4804880d265f834af1ff2f821ad5293e41fa0f8f59086c181fc38e" +checksum = "17d216c0ebf00e95acaf2b1e227e6cc900a5ce50fb81fa0743272851e88a788d" dependencies = [ - "assert_matches", - "borsh 1.5.3", - "num-derive", - "num-traits", - "solana-program", - "spl-token 6.0.0", - "spl-token-2022", - "thiserror 1.0.69", + "serde", + "serde_derive", + "solana-hash", ] [[package]] -name = "spl-discriminator" -version = "0.3.0" +name = "solana-slot-history" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38ea8b6dedb7065887f12d62ed62c1743aa70749e8558f963609793f6fb12bc" +checksum = "88cbcdf767891c6a40116a5ef8f7241000f074ece4ba80c8f00b4f62705fc8a4" dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator-derive", + "bv", + "serde", + "serde_derive", ] [[package]] -name = "spl-discriminator-derive" -version = "0.2.0" +name = "solana-stable-layout" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +checksum = "8a5305ca88fb5deb219cd88f04e24f3a131769417d7fcb11a8da1126a8f98d23" dependencies = [ - "quote", - "spl-discriminator-syn", - "syn 2.0.90", + "solana-instruction", + "solana-pubkey", ] [[package]] -name = "spl-discriminator-syn" -version = "0.2.0" +name = "solana-system-program" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +checksum = "242634cdc1eacaa83738cc100fdd583eb88f99cc2edcc900c8ebe57d77af51b1" dependencies = [ - "proc-macro2", - "quote", - "sha2 0.10.8", - "syn 2.0.90", - "thiserror 1.0.69", + "bincode", + "log", + "serde", + "serde_derive", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk", + "solana-type-overrides", ] [[package]] -name = "spl-memo" -version = "5.0.0" +name = "solana-timings" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0dba2f2bb6419523405d21c301a32c9f9568354d4742552e7972af801f4bdb3" +checksum = "a8a8e2f926d488c1e2a65cbc05544dcb68cfa88deb4d50f89db5bfbda7ff2419" dependencies = [ - "solana-program", + "eager", + "enum-iterator", + "solana-sdk", ] [[package]] -name = "spl-pod" -version = "0.3.1" +name = "solana-transaction-error" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c704c88fc457fa649ba3aabe195c79d885c3f26709efaddc453c8de352c90b87" +checksum = "37a4bea6d80b34fe6e785d19bf928fe103928d1f6c9935ec23bb6a9d4d7a33d2" dependencies = [ - "borsh 1.5.3", - "bytemuck", - "bytemuck_derive", - "solana-program", - "solana-zk-token-sdk", - "spl-program-error", + "serde", + "serde_derive", + "solana-instruction", + "solana-sanitize", ] [[package]] -name = "spl-program-error" -version = "0.5.0" +name = "solana-type-overrides" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7b28bed65356558133751cc32b48a7a5ddfc59ac4e941314630bbed1ac10532" +checksum = "2066f25d460d63801f91436c2640aaba4f2dc95aa18fe1e76f7f2c063e981d4e" dependencies = [ - "num-derive", - "num-traits", - "solana-program", - "spl-program-error-derive", - "thiserror 1.0.69", + "lazy_static", + "rand 0.8.5", ] [[package]] -name = "spl-program-error-derive" -version = "0.4.1" +name = "solana-vote" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +checksum = "5ab46788981765ee706094ca53ad8421aae0286a6b948e892fa7db88992a5373" dependencies = [ - "proc-macro2", - "quote", - "sha2 0.10.8", - "syn 2.0.90", + "itertools 0.12.1", + "log", + "serde", + "serde_derive", + "solana-sdk", + "thiserror 1.0.69", ] [[package]] -name = "spl-tlv-account-resolution" -version = "0.7.0" +name = "solana_rbpf" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a75a5f0fcc58126693ed78a17042e9dc53f07e357d6be91789f7d62aff61a4" +checksum = "1c1941b5ef0c3ce8f2ac5dd984d0fb1a97423c4ff2a02eec81e3913f02e2ac2b" dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", - "spl-type-length-value", + "byteorder", + "combine", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "scroll", + "thiserror 1.0.69", + "winapi", ] [[package]] -name = "spl-token" -version = "6.0.0" +name = "spin" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a0f06ac7f23dc0984931b1fe309468f14ea58e32660439c1cef19456f5d0e3" -dependencies = [ - "arrayref", - "bytemuck", - "num-derive", - "num-traits", - "num_enum", - "solana-program", - "thiserror 1.0.69", -] +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spl-token" @@ -5740,95 +3176,15 @@ dependencies = [ "arrayref", "bytemuck", "lazy_static", + "mollusk-svm", "num-derive", "num-traits", "num_enum", "proptest", "serial_test", "solana-program", - "solana-program-test", "solana-sdk", - "thiserror 2.0.7", -] - -[[package]] -name = "spl-token-2022" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c10f3483e48679619c76598d4e4aebb955bc49b0a5cc63323afbf44135c9bf" -dependencies = [ - "arrayref", - "bytemuck", - "num-derive", - "num-traits", - "num_enum", - "solana-program", - "solana-security-txt", - "solana-zk-token-sdk", - "spl-memo", - "spl-pod", - "spl-token 6.0.0", - "spl-token-group-interface", - "spl-token-metadata-interface", - "spl-transfer-hook-interface", - "spl-type-length-value", - "thiserror 1.0.69", -] - -[[package]] -name = "spl-token-group-interface" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8752b85a5ecc1d9f3a43bce3dd9a6a053673aacf5deb513d1cbb88d3534ffd" -dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", -] - -[[package]] -name = "spl-token-metadata-interface" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c2318ddff97e006ed9b1291ebec0750a78547f870f62a69c56fe3b46a5d8fc" -dependencies = [ - "borsh 1.5.3", - "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", - "spl-type-length-value", -] - -[[package]] -name = "spl-transfer-hook-interface" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a110f33d941275d9f868b96daaa993f1e73b6806cc8836e43075b4d3ad8338a7" -dependencies = [ - "arrayref", - "bytemuck", - "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", - "spl-tlv-account-resolution", - "spl-type-length-value", -] - -[[package]] -name = "spl-type-length-value" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdcd73ec187bc409464c60759232e309f83b52a18a9c5610bf281c9c6432918c" -dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", + "thiserror 2.0.8", ] [[package]] @@ -5837,39 +3193,11 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -5877,12 +3205,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "symlink" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" - [[package]] name = "syn" version = "1.0.109" @@ -5906,108 +3228,41 @@ dependencies = [ ] [[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tar" -version = "0.4.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "tarpc" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38a012bed6fb9681d3bf71ffaa4f88f3b4b9ed3198cda6e4c8462d24d4bb80" -dependencies = [ - "anyhow", - "fnv", - "futures", - "humantime", - "opentelemetry", - "pin-project", - "rand 0.8.5", - "serde", - "static_assertions", - "tarpc-plugins", - "thiserror 1.0.69", - "tokio", - "tokio-serde", - "tokio-util 0.6.10", - "tracing", - "tracing-opentelemetry", -] - -[[package]] -name = "tarpc-plugins" -version = "0.12.0" +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] -name = "task-local-extensions" -version = "0.1.4" +name = "system-configuration" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "pin-utils", + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -6020,7 +3275,7 @@ dependencies = [ "fastrand", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6032,12 +3287,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "termtree" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" - [[package]] name = "thiserror" version = "1.0.69" @@ -6049,11 +3298,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.7" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" +checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" dependencies = [ - "thiserror-impl 2.0.7", + "thiserror-impl 2.0.8", ] [[package]] @@ -6069,56 +3318,15 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.7" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" +checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" dependencies = [ "proc-macro2", "quote", "syn 2.0.90", ] -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinystr" version = "0.7.6" @@ -6131,9 +3339,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -6146,32 +3354,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", + "windows-sys 0.52.0", ] [[package]] @@ -6180,79 +3373,21 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.12", - "tokio", -] - -[[package]] -name = "tokio-serde" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" -dependencies = [ - "bincode", - "bytes", - "educe", - "futures-core", - "futures-sink", - "pin-project", - "serde", - "serde_json", -] - -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls 0.21.12", - "tokio", - "tokio-rustls", - "tungstenite", - "webpki-roots 0.25.4", -] - -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "slab", + "rustls", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -6266,15 +3401,15 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "toml_datetime", @@ -6283,65 +3418,27 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "log", "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-opentelemetry" -version = "0.17.4" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", - "opentelemetry", - "tracing", - "tracing-core", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", ] [[package]] @@ -6350,27 +3447,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.8.5", - "rustls 0.21.12", - "sha1", - "thiserror 1.0.69", - "url", - "utf-8", - "webpki-roots 0.24.0", -] - [[package]] name = "typenum" version = "1.17.0" @@ -6383,39 +3459,11 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" - [[package]] name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-width" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "universal-hash" -version = "0.5.1" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unreachable" @@ -6453,12 +3501,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf16_iter" version = "1.0.5" @@ -6471,23 +3513,11 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -6504,16 +3534,6 @@ dependencies = [ "libc", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -6562,12 +3582,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] @@ -6603,42 +3624,14 @@ checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki-root-certs" -version = "0.26.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd5da49bdf1f30054cfe0b8ce2958b8fbeb67c4d82c8967a598af481bef255c" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webpki-roots" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" -dependencies = [ - "rustls-webpki 0.101.7", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -6663,11 +3656,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6676,15 +3669,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.5", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -6700,7 +3684,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -6720,18 +3713,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -6742,9 +3735,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -6754,9 +3747,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -6766,15 +3759,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -6784,9 +3777,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -6796,9 +3789,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -6808,9 +3801,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -6820,15 +3813,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -6855,35 +3848,6 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" -[[package]] -name = "x509-parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" -dependencies = [ - "asn1-rs", - "base64 0.13.1", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror 1.0.69", - "time", -] - -[[package]] -name = "xattr" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" -dependencies = [ - "libc", - "linux-raw-sys", - "rustix", -] - [[package]] name = "yoke" version = "0.7.5" @@ -6905,23 +3869,24 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.90", - "synstructure 0.13.1", + "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", @@ -6946,14 +3911,14 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.90", - "synstructure 0.13.1", + "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" dependencies = [ "zeroize_derive", ] @@ -6990,31 +3955,3 @@ dependencies = [ "quote", "syn 2.0.90", ] - -[[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/program/Cargo.toml b/program/Cargo.toml index cfff306..21b18ad 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -22,9 +22,9 @@ thiserror = "2.0" [dev-dependencies] lazy_static = "1.5.0" +mollusk-svm = "0.0.13" proptest = "1.5" serial_test = "3.2.0" -solana-program-test = "2.1.0" solana-sdk = "2.1.0" [lib] diff --git a/program/tests/action.rs b/program/tests/action.rs deleted file mode 100644 index 0a67538..0000000 --- a/program/tests/action.rs +++ /dev/null @@ -1,140 +0,0 @@ -use { - solana_program_test::BanksClient, - solana_sdk::{ - hash::Hash, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, - transport::TransportError, - }, - spl_token::{ - id, instruction, - state::{Account, Mint}, - }, -}; - -pub async fn create_mint( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - pool_mint: &Keypair, - manager: &Pubkey, - decimals: u8, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(Mint::LEN); - - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &pool_mint.pubkey(), - mint_rent, - Mint::LEN as u64, - &id(), - ), - instruction::initialize_mint(&id(), &pool_mint.pubkey(), manager, None, decimals) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, pool_mint], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn create_account( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - account: &Keypair, - pool_mint: &Pubkey, - owner: &Pubkey, -) -> Result<(), TransportError> { - let rent = banks_client.get_rent().await.unwrap(); - let account_rent = rent.minimum_balance(Account::LEN); - - let transaction = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &payer.pubkey(), - &account.pubkey(), - account_rent, - Account::LEN as u64, - &id(), - ), - instruction::initialize_account(&id(), &account.pubkey(), pool_mint, owner).unwrap(), - ], - Some(&payer.pubkey()), - &[payer, account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn mint_to( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - mint: &Pubkey, - account: &Pubkey, - mint_authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::mint_to(&id(), mint, account, &mint_authority.pubkey(), &[], amount) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, mint_authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn transfer( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - source: &Pubkey, - destination: &Pubkey, - authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::transfer(&id(), source, destination, &authority.pubkey(), &[], amount) - .unwrap(), - ], - Some(&payer.pubkey()), - &[payer, authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} - -pub async fn burn( - banks_client: &mut BanksClient, - payer: &Keypair, - recent_blockhash: Hash, - mint: &Pubkey, - account: &Pubkey, - authority: &Keypair, - amount: u64, -) -> Result<(), TransportError> { - let transaction = Transaction::new_signed_with_payer( - &[instruction::burn(&id(), account, mint, &authority.pubkey(), &[], amount).unwrap()], - Some(&payer.pubkey()), - &[payer, authority], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await?; - Ok(()) -} diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs index 009fb1e..ab5de7c 100644 --- a/program/tests/assert_instruction_count.rs +++ b/program/tests/assert_instruction_count.rs @@ -1,332 +1,201 @@ #![cfg(feature = "test-sbf")] -mod action; +mod setup; + use { - solana_program_test::{processor, tokio, ProgramTest}, + mollusk_svm::{result::Check, Mollusk}, solana_sdk::{ + account::{AccountSharedData, ReadableAccount}, program_pack::Pack, pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, }, spl_token::{ id, instruction, - processor::Processor, state::{Account, Mint}, }, }; const TRANSFER_AMOUNT: u64 = 1_000_000_000_000_000; -#[tokio::test] -async fn initialize_mint() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(5_000); // last known 2252 - let (banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn initialize_mint() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 5_000; // last known 2252 - let owner_key = Pubkey::new_unique(); - let mint = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); let decimals = 9; - let rent = banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(Mint::LEN); - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &mint.pubkey(), - mint_rent, - Mint::LEN as u64, - &id(), - )], - Some(&payer.pubkey()), - &[&payer, &mint], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); + let mint_account = { + let space = Mint::LEN; + let lamports = mollusk.sysvars.rent.minimum_balance(space); + AccountSharedData::new(lamports, space, &id()) + }; - let transaction = Transaction::new_signed_with_payer( + mollusk.process_and_validate_instruction( + &instruction::initialize_mint(&id(), &mint, &owner, None, decimals).unwrap(), + &[ + (mint, mint_account), + mollusk.sysvars.keyed_account_for_rent_sysvar(), + ], &[ - instruction::initialize_mint(&id(), &mint.pubkey(), &owner_key, None, decimals) - .unwrap(), + Check::success(), + Check::account(&mint) + .data(setup::setup_mint_account(Some(&owner), None, 0, decimals).data()) + .build(), ], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, ); - banks_client.process_transaction(transaction).await.unwrap(); } -#[tokio::test] -async fn initialize_account() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 3284 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn initialize_account() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 6_000; // last known 3284 - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); let decimals = 9; - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - let rent = banks_client.get_rent().await.unwrap(); - let account_rent = rent.minimum_balance(Account::LEN); - let transaction = Transaction::new_signed_with_payer( - &[system_instruction::create_account( - &payer.pubkey(), - &account.pubkey(), - account_rent, - Account::LEN as u64, - &id(), - )], - Some(&payer.pubkey()), - &[&payer, &account], - recent_blockhash, - ); - banks_client.process_transaction(transaction).await.unwrap(); + let mint_account = setup::setup_mint_account(None, None, 0, decimals); + let token_account = { + let space = Account::LEN; + let lamports = mollusk.sysvars.rent.minimum_balance(space); + AccountSharedData::new(lamports, space, &id()) + }; - let transaction = Transaction::new_signed_with_payer( - &[instruction::initialize_account( - &id(), - &account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer], - recent_blockhash, + mollusk.process_and_validate_instruction( + &instruction::initialize_account(&id(), &account, &mint, &owner).unwrap(), + &[ + (account, token_account), + (mint, mint_account), + (owner, AccountSharedData::default()), + mollusk.sysvars.keyed_account_for_rent_sysvar(), + ], + &[ + Check::success(), + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .build(), + ], ); - banks_client.process_transaction(transaction).await.unwrap(); } -#[tokio::test] -async fn mint_to() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 2668 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn mint_to() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 6_000; // last known 2668 - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); let decimals = 9; - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); + let mint_account = setup::setup_mint_account(Some(&owner), None, 0, decimals); + let token_account = setup::setup_token_account(&mint, &owner, 0); - let transaction = Transaction::new_signed_with_payer( - &[instruction::mint_to( - &id(), - &mint.pubkey(), - &account.pubkey(), - &owner.pubkey(), - &[], - TRANSFER_AMOUNT, - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer, &owner], - recent_blockhash, + mollusk.process_and_validate_instruction( + &instruction::mint_to(&id(), &mint, &account, &owner, &[], TRANSFER_AMOUNT).unwrap(), + &[ + (mint, mint_account), + (account, token_account), + (owner, AccountSharedData::default()), + ], + &[ + Check::success(), + Check::account(&mint) + .data( + setup::setup_mint_account(Some(&owner), None, TRANSFER_AMOUNT, decimals).data(), + ) + .build(), + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, TRANSFER_AMOUNT).data()) + .build(), + ], ); - banks_client.process_transaction(transaction).await.unwrap(); } -#[tokio::test] -async fn transfer() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(7_000); // last known 2972 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; - - let owner = Keypair::new(); - let mint = Keypair::new(); - let source = Keypair::new(); - let destination = Keypair::new(); - let decimals = 9; +#[test] +fn transfer() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 7_000; // last known 2972 - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &source, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &destination, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let source = Pubkey::new_unique(); + let destination = Pubkey::new_unique(); - action::mint_to( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &source.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); + let source_token_account = setup::setup_token_account(&mint, &owner, TRANSFER_AMOUNT); + let destination_token_account = setup::setup_token_account(&mint, &owner, 0); - action::transfer( - &mut banks_client, - &payer, - recent_blockhash, - &source.pubkey(), - &destination.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); + mollusk.process_and_validate_instruction( + &instruction::transfer(&id(), &source, &destination, &owner, &[], TRANSFER_AMOUNT).unwrap(), + &[ + (source, source_token_account), + (destination, destination_token_account), + (owner, AccountSharedData::default()), + ], + &[ + Check::success(), + Check::account(&source) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .build(), + Check::account(&destination) + .data(setup::setup_token_account(&mint, &owner, TRANSFER_AMOUNT).data()) + .build(), + ], + ); } -#[tokio::test] -async fn burn() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 2655 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn burn() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 6_000; // last known 2655 - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); let decimals = 9; - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); - - action::mint_to( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &account.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); + let mint_account = setup::setup_mint_account(None, None, TRANSFER_AMOUNT, decimals); + let token_account = setup::setup_token_account(&mint, &owner, TRANSFER_AMOUNT); - action::burn( - &mut banks_client, - &payer, - recent_blockhash, - &mint.pubkey(), - &account.pubkey(), - &owner, - TRANSFER_AMOUNT, - ) - .await - .unwrap(); + mollusk.process_and_validate_instruction( + &instruction::burn(&id(), &account, &mint, &owner, &[], TRANSFER_AMOUNT).unwrap(), + &[ + (mint, mint_account), + (account, token_account), + (owner, AccountSharedData::default()), + ], + &[ + Check::success(), + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .build(), + ], + ); } -#[tokio::test] -async fn close_account() { - let mut pt = ProgramTest::new("spl_token", id(), processor!(Processor::process)); - pt.set_compute_max_units(6_000); // last known 1783 - let (mut banks_client, payer, recent_blockhash) = pt.start().await; +#[test] +fn close_account() { + let mut mollusk = Mollusk::new(&id(), "spl_token"); + mollusk.compute_budget.compute_unit_limit = 6_000; // last known 1783 - let owner = Keypair::new(); - let mint = Keypair::new(); - let account = Keypair::new(); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); let decimals = 9; - action::create_mint( - &mut banks_client, - &payer, - recent_blockhash, - &mint, - &owner.pubkey(), - decimals, - ) - .await - .unwrap(); - action::create_account( - &mut banks_client, - &payer, - recent_blockhash, - &account, - &mint.pubkey(), - &owner.pubkey(), - ) - .await - .unwrap(); + let mint_account = setup::setup_mint_account(None, None, 0, decimals); + let token_account = setup::setup_token_account(&mint, &owner, 0); - let transaction = Transaction::new_signed_with_payer( - &[instruction::close_account( - &id(), - &account.pubkey(), - &owner.pubkey(), - &owner.pubkey(), - &[], - ) - .unwrap()], - Some(&payer.pubkey()), - &[&payer, &owner], - recent_blockhash, + mollusk.process_and_validate_instruction( + &instruction::close_account(&id(), &account, &owner, &owner, &[]).unwrap(), + &[ + (mint, mint_account), + (account, token_account), + (owner, AccountSharedData::default()), + ], + &[Check::success(), Check::account(&account).closed().build()], ); - banks_client.process_transaction(transaction).await.unwrap(); } diff --git a/program/tests/close_account.rs b/program/tests/close_account.rs index 8425fe2..7cfbb06 100644 --- a/program/tests/close_account.rs +++ b/program/tests/close_account.rs @@ -1,200 +1,111 @@ #![cfg(feature = "test-sbf")] +mod setup; + use { - solana_program_test::{processor, tokio, ProgramTest, ProgramTestContext}, + mollusk_svm::{result::Check, Mollusk}, solana_sdk::{ - instruction::InstructionError, + account::{AccountSharedData, ReadableAccount}, + program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, - signature::Signer, - signer::keypair::Keypair, - system_instruction, - transaction::{Transaction, TransactionError}, - }, - spl_token::{ - instruction, - processor::Processor, - state::{Account, Mint}, + system_instruction, system_program, }, + spl_token::{instruction, state::Account}, }; -async fn setup_mint_and_account( - context: &mut ProgramTestContext, - mint: &Keypair, - token_account: &Keypair, - owner: &Pubkey, - token_program_id: &Pubkey, -) { - let rent = context.banks_client.get_rent().await.unwrap(); - let mint_authority_pubkey = Pubkey::new_unique(); +#[test] +fn success_init_after_close_account() { + let mollusk = Mollusk::new(&spl_token::id(), "spl_token"); - let space = Mint::LEN; - let tx = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &context.payer.pubkey(), - &mint.pubkey(), - rent.minimum_balance(space), - space as u64, - token_program_id, - ), - instruction::initialize_mint( - token_program_id, - &mint.pubkey(), - &mint_authority_pubkey, - None, - 9, - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, mint], - context.last_blockhash, - ); - context.banks_client.process_transaction(tx).await.unwrap(); - let space = Account::LEN; - let tx = Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &context.payer.pubkey(), - &token_account.pubkey(), - rent.minimum_balance(space), - space as u64, - token_program_id, - ), - instruction::initialize_account( - token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - owner, - ) - .unwrap(), - ], - Some(&context.payer.pubkey()), - &[&context.payer, token_account], - context.last_blockhash, - ); - context.banks_client.process_transaction(tx).await.unwrap(); -} + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); + let destination = Pubkey::new_unique(); + let decimals = 9; -#[tokio::test] -async fn success_init_after_close_account() { - let program_test = - ProgramTest::new("spl_token", spl_token::id(), processor!(Processor::process)); - let mut context = program_test.start_with_context().await; - let mint = Keypair::new(); - let token_account = Keypair::new(); - let owner = Keypair::new(); - let token_program_id = spl_token::id(); - setup_mint_and_account( - &mut context, - &mint, - &token_account, - &owner.pubkey(), - &token_program_id, - ) - .await; + let owner_account = AccountSharedData::new(1_000_000_000, 0, &system_program::id()); + let mint_account = setup::setup_mint_account(None, None, 0, decimals); + let token_account = setup::setup_token_account(&mint, &owner, 0); - let destination = Pubkey::new_unique(); - let tx = Transaction::new_signed_with_payer( + let expected_destination_lamports = token_account.lamports(); + + mollusk.process_and_validate_instruction_chain( &[ - instruction::close_account( - &token_program_id, - &token_account.pubkey(), - &destination, - &owner.pubkey(), - &[], - ) - .unwrap(), + instruction::close_account(&spl_token::id(), &account, &destination, &owner, &[]) + .unwrap(), system_instruction::create_account( - &context.payer.pubkey(), - &token_account.pubkey(), + &owner, + &account, 1_000_000_000, Account::LEN as u64, - &token_program_id, + &spl_token::id(), ), - instruction::initialize_account( - &token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap(), + instruction::initialize_account(&spl_token::id(), &account, &mint, &owner).unwrap(), + ], + &[ + (mint, mint_account), + (account, token_account), + (owner, owner_account), + (destination, AccountSharedData::default()), + mollusk.sysvars.keyed_account_for_rent_sysvar(), + ], + &[ + Check::success(), + // Account successfully re-initialized. + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .owner(&spl_token::id()) + .build(), + // The destination should have the lamports from the closed account. + Check::account(&destination) + .lamports(expected_destination_lamports) + .build(), ], - Some(&context.payer.pubkey()), - &[&context.payer, &owner, &token_account], - context.last_blockhash, ); - context.banks_client.process_transaction(tx).await.unwrap(); - let destination = context - .banks_client - .get_account(destination) - .await - .unwrap() - .unwrap(); - assert!(destination.lamports > 0); } -#[tokio::test] -async fn fail_init_after_close_account() { - let program_test = - ProgramTest::new("spl_token", spl_token::id(), processor!(Processor::process)); - let mut context = program_test.start_with_context().await; - let mint = Keypair::new(); - let token_account = Keypair::new(); - let owner = Keypair::new(); - let token_program_id = spl_token::id(); - setup_mint_and_account( - &mut context, - &mint, - &token_account, - &owner.pubkey(), - &token_program_id, - ) - .await; +#[test] +fn fail_init_after_close_account() { + let mollusk = Mollusk::new(&spl_token::id(), "spl_token"); + let owner = Pubkey::new_unique(); + let mint = Pubkey::new_unique(); + let account = Pubkey::new_unique(); let destination = Pubkey::new_unique(); - let tx = Transaction::new_signed_with_payer( + let decimals = 9; + + let owner_account = AccountSharedData::new(1_000_000_000, 0, &system_program::id()); + let mint_account = setup::setup_mint_account(None, None, 0, decimals); + let token_account = setup::setup_token_account(&mint, &owner, 0); + + let expected_destination_lamports = token_account.lamports(); + + mollusk.process_and_validate_instruction_chain( &[ - instruction::close_account( - &token_program_id, - &token_account.pubkey(), - &destination, - &owner.pubkey(), - &[], - ) - .unwrap(), - system_instruction::transfer( - &context.payer.pubkey(), - &token_account.pubkey(), - 1_000_000_000, - ), - instruction::initialize_account( - &token_program_id, - &token_account.pubkey(), - &mint.pubkey(), - &owner.pubkey(), - ) - .unwrap(), + instruction::close_account(&spl_token::id(), &account, &destination, &owner, &[]) + .unwrap(), + system_instruction::transfer(&owner, &account, 1_000_000_000), + instruction::initialize_account(&spl_token::id(), &account, &mint, &owner).unwrap(), + ], + &[ + (mint, mint_account), + (account, token_account), + (owner, owner_account), + (destination, AccountSharedData::default()), + mollusk.sysvars.keyed_account_for_rent_sysvar(), + ], + &[ + Check::err(ProgramError::InvalidAccountData), + // Account not re-initialized. + Check::account(&account) + .lamports(1_000_000_000) + .owner(&system_program::id()) + .build(), + // The destination should have the lamports from the closed account. + Check::account(&destination) + .lamports(expected_destination_lamports) + .build(), ], - Some(&context.payer.pubkey()), - &[&context.payer, &owner], - context.last_blockhash, - ); - let error = context - .banks_client - .process_transaction(tx) - .await - .unwrap_err() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError(2, InstructionError::InvalidAccountData) ); - assert!(context - .banks_client - .get_account(destination) - .await - .unwrap() - .is_none()); } diff --git a/program/tests/setup.rs b/program/tests/setup.rs new file mode 100644 index 0000000..df79381 --- /dev/null +++ b/program/tests/setup.rs @@ -0,0 +1,69 @@ +#![cfg(feature = "test-sbf")] + +use { + solana_sdk::{ + account::{Account as SolanaAccount, AccountSharedData}, + program_pack::Pack, + pubkey::Pubkey, + rent::Rent, + }, + spl_token::state::{Account, AccountState, Mint}, +}; + +pub fn setup_mint_account( + mint_authority: Option<&Pubkey>, + freeze_authority: Option<&Pubkey>, + supply: u64, + decimals: u8, +) -> AccountSharedData { + let data = { + let mut data = vec![0; Mint::LEN]; + let state = Mint { + mint_authority: mint_authority.cloned().into(), + supply, + decimals, + is_initialized: true, + freeze_authority: freeze_authority.cloned().into(), + }; + state.pack_into_slice(&mut data); + data + }; + + let space = data.len(); + let lamports = Rent::default().minimum_balance(space); + + AccountSharedData::from(SolanaAccount { + lamports, + data, + owner: spl_token::id(), + ..Default::default() + }) +} + +pub fn setup_token_account(mint: &Pubkey, owner: &Pubkey, amount: u64) -> AccountSharedData { + let data = { + let mut data = vec![0; Account::LEN]; + let state = Account { + mint: *mint, + owner: *owner, + amount, + delegate: None.into(), + state: AccountState::Initialized, + is_native: None.into(), + delegated_amount: 0, + close_authority: None.into(), + }; + state.pack_into_slice(&mut data); + data + }; + + let space = data.len(); + let lamports = Rent::default().minimum_balance(space); + + AccountSharedData::from(SolanaAccount { + lamports, + data, + owner: spl_token::id(), + ..Default::default() + }) +} From 6d6a610571854beccadade5d437e8c4dcfb39f9e Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Mon, 13 Jan 2025 20:58:52 +0000 Subject: [PATCH 260/335] tests: Move processor tests (#17) Move processor tests --- program/src/processor.rs | 5695 +---------------------------------- program/tests/processor.rs | 5705 ++++++++++++++++++++++++++++++++++++ 2 files changed, 5712 insertions(+), 5688 deletions(-) create mode 100644 program/tests/processor.rs diff --git a/program/src/processor.rs b/program/src/processor.rs index 4702693..56e9e4a 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -1042,18 +1042,7 @@ fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { mod tests { use { super::*, - crate::instruction::*, - serial_test::serial, - solana_program::{ - account_info::IntoAccountInfo, - clock::Epoch, - instruction::Instruction, - program_error::{self, PrintProgramError}, - sysvar::rent, - }, - solana_sdk::account::{ - create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, - }, + solana_program::{clock::Epoch, program_error::PrintProgramError}, std::sync::{Arc, RwLock}, }; @@ -1061,99 +1050,10 @@ mod tests { static ref EXPECTED_DATA: Arc>> = Arc::new(RwLock::new(Vec::new())); } - fn set_expected_data(expected_data: Vec) { - *EXPECTED_DATA.write().unwrap() = expected_data; - } - - struct SyscallStubs {} - impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs { - fn sol_log(&self, _message: &str) {} - - fn sol_invoke_signed( - &self, - _instruction: &Instruction, - _account_infos: &[AccountInfo], - _signers_seeds: &[&[&[u8]]], - ) -> ProgramResult { - Err(ProgramError::Custom(42)) // Not supported - } - - fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - #[allow(deprecated)] - fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - fn sol_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 { - unsafe { - *(var_addr as *mut _ as *mut Rent) = Rent::default(); - } - solana_program::entrypoint::SUCCESS - } - - fn sol_set_return_data(&self, data: &[u8]) { - assert_eq!(&*EXPECTED_DATA.write().unwrap(), data) - } - } - - fn do_process_instruction( - instruction: Instruction, - accounts: Vec<&mut SolanaAccount>, - ) -> ProgramResult { - { - use std::sync::Once; - static ONCE: Once = Once::new(); - - ONCE.call_once(|| { - solana_sdk::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {})); - }); - } - - let mut meta = instruction - .accounts - .iter() - .zip(accounts) - .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) - .collect::>(); - - let account_infos = create_is_signer_account_infos(&mut meta); - Processor::process(&instruction.program_id, &account_infos, &instruction.data) - } - - fn do_process_instruction_dups( - instruction: Instruction, - account_infos: Vec, - ) -> ProgramResult { - Processor::process(&instruction.program_id, &account_infos, &instruction.data) - } - fn return_token_error_as_program_error() -> ProgramError { TokenError::MintMismatch.into() } - fn rent_sysvar() -> SolanaAccount { - create_account_for_test(&Rent::default()) - } - - fn mint_minimum_balance() -> u64 { - Rent::default().minimum_balance(Mint::get_packed_len()) - } - - fn account_minimum_balance() -> u64 { - Rent::default().minimum_balance(Account::get_packed_len()) - } - - fn multisig_minimum_balance() -> u64 { - Rent::default().minimum_balance(Multisig::get_packed_len()) - } - #[test] fn test_print_error() { let error = return_token_error_as_program_error(); @@ -1275,4021 +1175,12 @@ mod tests { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, - ]; - assert_eq!(packed, expect); - let unpacked = Multisig::unpack(&packed).unwrap(); - assert_eq!(unpacked, check); - } - - #[test] - fn test_initialize_mint() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // mint is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar] - ) - ); - - mint_account.lamports = mint_minimum_balance(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account, &mut rent_sysvar] - ) - ); - - // create another mint that can freeze - do_process_instruction( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); - assert_eq!(mint.freeze_authority, COption::Some(owner_key)); - } - - #[test] - fn test_initialize_mint2() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - - // mint is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account] - ) - ); - - mint_account.lamports = mint_minimum_balance(); - - // create new mint - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account] - ) - ); - - // create another mint that can freeze - do_process_instruction( - initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); - assert_eq!(mint.freeze_authority, COption::Some(owner_key)); - } - - #[test] - fn test_initialize_mint_account() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // account is not rent exempt - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - - account_account.lamports = account_minimum_balance(); - - // mint is not valid (not initialized) - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - mint_account.owner = program_id; - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create twice - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar - ], - ) - ); - } - - #[test] - fn test_transfer_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into(); - let account4_key = Pubkey::new_unique(); - let mut account4_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // create another account - do_process_instruction_dups( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - account2_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner transfer - do_process_instruction_dups( - transfer( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate transfer - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.amount = 1000; - account.delegated_amount = 1000; - account.delegate = COption::Some(account1_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - - do_process_instruction_dups( - transfer( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // test destination-owner transfer - do_process_instruction_dups( - initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], - ) - .unwrap(); - - account1_info.is_signer = false; - account2_info.is_signer = true; - do_process_instruction_dups( - transfer( - &program_id, - &account3_key, - &account2_key, - &account2_key, - &[], - 500, - ) - .unwrap(), - vec![ - account3_info.clone(), - account2_info.clone(), - account2_info.clone(), - ], - ) - .unwrap(); - - // destination-owner TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account3_key, - &mint_key, - &account2_key, - &account2_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - account2_info.clone(), - ], - ) - .unwrap(); - - // test source-multisig signer - do_process_instruction_dups( - initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(), - vec![ - multisig_info.clone(), - rent_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(), - vec![ - account4_info.clone(), - mint_info.clone(), - multisig_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account4_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-multisig-signer transfer - do_process_instruction_dups( - transfer( - &program_id, - &account4_key, - &account2_key, - &multisig_key, - &[&account4_key], - 500, - ) - .unwrap(), - vec![ - account4_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - - // source-multisig-signer TransferChecked - do_process_instruction_dups( - transfer_checked( - &program_id, - &account4_key, - &mint_key, - &account2_key, - &multisig_key, - &[&account4_key], - 500, - 2, - ) - .unwrap(), - vec![ - account4_info.clone(), - mint_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account4_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_transfer() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // missing signer - let mut instruction = transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // mismatch mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &mismatch_key, - &owner_key, - &[], - 1000 - ) - .unwrap(), - vec![ - &mut account_account, - &mut mismatch_account, - &mut owner_account, - ], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner2_key, - &[], - 1000 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - account_account.owner = program_id; - - // account 2 not owned by program - let not_program_id = Pubkey::new_unique(); - account2_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - account2_account.owner = program_id; - - // transfer - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 1000, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // transfer half back - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &mint_key, - &account_key, - &owner_key, - &[], - 1, - 10 // <-- incorrect decimals - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut account_account, - &mut owner_account, - ], - ) - ); - - // incorrect mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &account3_key, // <-- incorrect mint - &account_key, - &owner_key, - &[], - 1, - 2 - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account3_account, // <-- incorrect mint - &mut account_account, - &mut owner_account, - ], - ) - ); - // transfer rest with explicit decimals - do_process_instruction( - transfer_checked( - &program_id, - &account2_key, - &mint_key, - &account_key, - &owner_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut account_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner_account, - ], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // not a delegate of source account - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner2_key, // <-- incorrect owner or delegate - &[], - 1, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 101 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - - // transfer via delegate - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - .unwrap(); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 1 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - - // transfer rest - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 900, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // insufficient funds in source account via delegate - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &delegate_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut delegate_account, - ], - ) - ); - } - - #[test] - fn test_self_transfer() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - let account_info = (&account_key, false, &mut account_account).into_account_info(); - let account3_info = (&account3_key, false, &mut account3_account).into_account_info(); - let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info(); - let owner_info = (&owner_key, true, &mut owner_account).into_account_info(); - let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info(); - let mint_info = (&mint_key, false, &mut mint_account).into_account_info(); - - // transfer - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // transfer checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // missing signer - let mut owner_no_sign_info = owner_info.clone(); - let mut instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_no_sign_info.key, - &[], - 1000, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - owner_no_sign_info.is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_no_sign_info.clone(), - ], - &instruction.data, - ) - ); - - // missing signer checked - let mut instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_no_sign_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - instruction.accounts[3].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_no_sign_info, - ], - &instruction.data, - ) - ); - - // missing owner - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner2_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner2_info.clone(), - ], - &instruction.data, - ) - ); - - // missing owner checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner2_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner2_info.clone(), - ], - &instruction.data, - ) - ); - - // insufficient funds - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1001, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // insufficient funds checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1001, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // incorrect decimals - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1, - 10, // <-- incorrect decimals - ) - .unwrap(); - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // incorrect mint - let instruction = transfer_checked( - &program_id, - account_info.key, - account3_info.key, // <-- incorrect mint - account_info.key, - owner_info.key, - &[], - 1, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::MintMismatch.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account3_info.clone(), // <-- incorrect mint - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - - // approve delegate - let instruction = approve( - &program_id, - account_info.key, - delegate_info.key, - owner_info.key, - &[], - 100, - ) - .unwrap(); - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - delegate_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - .unwrap(); - - // delegate transfer - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - delegate_info.key, - &[], - 100, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - assert_eq!(account.delegated_amount, 100); - - // delegate transfer checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - delegate_info.key, - &[], - 100, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - assert_eq!(account.delegated_amount, 100); - - // delegate insufficient funds - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - delegate_info.key, - &[], - 101, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - - // delegate insufficient funds checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - delegate_info.key, - &[], - 101, - 2, - ) - .unwrap(); - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - delegate_info.clone(), - ], - &instruction.data, - ) - ); - - // owner transfer with delegate assigned - let instruction = transfer( - &program_id, - account_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - - // owner transfer with delegate assigned checked - let instruction = transfer_checked( - &program_id, - account_info.key, - mint_info.key, - account_info.key, - owner_info.key, - &[], - 1000, - 2, - ) - .unwrap(); - assert_eq!( - Ok(()), - Processor::process( - &instruction.program_id, - &[ - account_info.clone(), - mint_info.clone(), - account_info.clone(), - owner_info.clone(), - ], - &instruction.data, - ) - ); - // no balance change... - let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); - assert_eq!(account.amount, 1000); - } - - #[test] - fn test_mintable_token_with_zero_supply() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint-able token with zero supply - let decimals = 2; - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!( - mint, - Mint { - mint_authority: COption::Some(owner_key), - supply: 0, - decimals, - is_initialized: true, - freeze_authority: COption::None, - } - ); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to 2, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - mint_to_checked( - &program_id, - &mint_key, - &account_key, - &owner_key, - &[], - 42, - decimals + 1 - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to 2 - do_process_instruction( - mint_to_checked( - &program_id, - &mint_key, - &account_key, - &owner_key, - &[], - 42, - decimals, - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - let _ = Mint::unpack(&mint_account.data).unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 84); - } - - #[test] - fn test_approve_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // create another account - do_process_instruction_dups( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - account2_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner approve - do_process_instruction_dups( - approve( - &program_id, - &account1_key, - &account2_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner approve_checked - do_process_instruction_dups( - approve_checked( - &program_id, - &account1_key, - &mint_key, - &account2_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account2_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner revoke - do_process_instruction_dups( - revoke(&program_id, &account1_key, &account1_key, &[]).unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - - // test source-multisig signer - do_process_instruction_dups( - initialize_multisig(&program_id, &multisig_key, &[&account3_key], 1).unwrap(), - vec![ - multisig_info.clone(), - rent_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - initialize_account(&program_id, &account3_key, &mint_key, &multisig_key).unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - multisig_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-multisig-signer approve - do_process_instruction_dups( - approve( - &program_id, - &account3_key, - &account2_key, - &multisig_key, - &[&account3_key], - 500, - ) - .unwrap(), - vec![ - account3_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - // source-multisig-signer approve_checked - do_process_instruction_dups( - approve_checked( - &program_id, - &account3_key, - &mint_key, - &account2_key, - &multisig_key, - &[&account3_key], - 500, - 2, - ) - .unwrap(), - vec![ - account3_info.clone(), - mint_info.clone(), - account2_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - - // source-owner multisig-signer - do_process_instruction_dups( - revoke(&program_id, &account3_key, &multisig_key, &[&account3_key]).unwrap(), - vec![ - account3_info.clone(), - multisig_info.clone(), - account3_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_approve() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // missing signer - let mut instruction = approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // no owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner2_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner2_account, - ], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // approve delegate 2, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &owner_key, - &[], - 100, - 0 // <-- incorrect decimals - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // approve delegate 2, with incorrect mint - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &account2_key, // <-- bad mint - &delegate_key, - &owner_key, - &[], - 100, - 0 - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, // <-- bad mint - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // approve delegate 2 - do_process_instruction( - approve_checked( - &program_id, - &account_key, - &mint_key, - &delegate_key, - &owner_key, - &[], - 100, - 2, - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // revoke delegate - do_process_instruction( - revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - } - - #[test] - fn test_set_authority_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // set mint_authority when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::MintTokens, - &mint_key, - &[], - ) - .unwrap(), - vec![mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // set freeze_authority when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::FreezeAccount, - &mint_key, - &[], - ) - .unwrap(), - vec![mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // set account owner when currently self - do_process_instruction_dups( - set_authority( - &program_id, - &account1_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &account1_key, - &[], - ) - .unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - - // set close_authority when currently self - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(account1_key); - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - - do_process_instruction_dups( - set_authority( - &program_id, - &account1_key, - Some(&owner_key), - AuthorityType::CloseAccount, - &account1_key, - &[], - ) - .unwrap(), - vec![account1_info.clone(), account1_info.clone()], - ) - .unwrap(); - } - - #[test] - fn test_set_authority() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let owner3_key = Pubkey::new_unique(); - let mut owner3_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create mint with owner and freeze_authority - do_process_instruction( - initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - - // invalid account - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint2_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &owner2_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - ); - - // owner did not sign - let mut instruction = set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],) - ); - - // wrong authority type - assert_eq!( - Err(TokenError::AuthorityTypeNotSupported.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // account owner may not be set to None - assert_eq!( - Err(TokenError::InvalidInstruction.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - None, - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // set delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &owner2_key, - &owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut account_account, - &mut owner2_account, - &mut owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.delegate, COption::Some(owner2_key)); - assert_eq!(account.delegated_amount, u64::MAX); - - // set owner - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner3_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // check delegate cleared - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.delegate, COption::None); - assert_eq!(account.delegated_amount, 0); - - // set owner without existing delegate - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner3_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner3_account], - ) - .unwrap(); - - // set close_authority - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::CloseAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - .unwrap(); - - // close_authority may be set to None - do_process_instruction( - set_authority( - &program_id, - &account_key, - None, - AuthorityType::CloseAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner2_account], - ) - .unwrap(); - - // wrong owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner3_key), - AuthorityType::MintTokens, - &owner2_key, - &[] - ) - .unwrap(), - vec![&mut mint_account, &mut owner2_account], - ) - ); - - // owner did not sign - let mut instruction = set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],) - ); - - // cannot freeze - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - ); - - // set owner - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - .unwrap(); - - // set owner to None - do_process_instruction( - set_authority( - &program_id, - &mint_key, - None, - AuthorityType::MintTokens, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner2_account], - ) - .unwrap(); - - // test unsetting mint_authority is one-way operation - assert_eq!( - Err(TokenError::FixedSupply.into()), - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::MintTokens, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - ); - - // set freeze_authority - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner_account], - ) - .unwrap(); - - // test unsetting freeze_authority is one-way operation - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - None, - AuthorityType::FreezeAccount, - &owner2_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner2_account], - ) - .unwrap(); - - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - set_authority( - &program_id, - &mint2_key, - Some(&owner2_key), - AuthorityType::FreezeAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint2_account, &mut owner2_account], - ) - ); - } - - #[test] - fn test_mint_to_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &owner_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - owner_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint_to when mint_authority is self - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(), - vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint_to_checked when mint_authority is self - do_process_instruction_dups( - mint_to_checked(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), - vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint_to when mint_authority is account owner - let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap(); - mint.mint_authority = COption::Some(account1_key); - Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - mint_to( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 42, - ) - .unwrap(), - vec![ - mint_info.clone(), - account1_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint_to_checked when mint_authority is account owner - do_process_instruction_dups( - mint_to( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 42, - ) - .unwrap(), - vec![ - mint_info.clone(), - account1_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_mint_to() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let uninitialized_key = Pubkey::new_unique(); - let mut uninitialized_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // mint to - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 42); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // mint to another account to test supply accumulation - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 84); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // missing signer - let mut instruction = - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(); - instruction.accounts[2].is_signer = false; - assert_eq!( - Err(ProgramError::MissingRequiredSignature), - do_process_instruction( - instruction, - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - ); - - // mismatch account - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut mismatch_account, &mut owner_account], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut owner2_account, - ], - ) - ); - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - mint_account.owner = program_id; - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - account_account.owner = program_id; - - // uninitialized destination account - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &uninitialized_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![ - &mut mint_account, - &mut uninitialized_account, - &mut owner_account, - ], - ) - ); - - // unset mint_authority and test minting fails - do_process_instruction( - set_authority( - &program_id, - &mint_key, - None, - AuthorityType::MintTokens, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut mint_account, &mut owner_account], - ) - .unwrap(); - assert_eq!( - Err(TokenError::FixedSupply.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), - vec![&mut mint_account, &mut account2_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_burn_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // mint to account - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - - // source-owner burn - do_process_instruction_dups( - burn( - &program_id, - &mint_key, - &account1_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-owner burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint-owner burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.owner = mint_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint-owner burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &mint_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // source-delegate burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.delegated_amount = 1000; - account.delegate = COption::Some(account1_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // source-delegate burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &account1_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // mint-delegate burn - do_process_instruction_dups( - mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), - vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.delegated_amount = 1000; - account.delegate = COption::Some(mint_key); - account.owner = owner_key; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - - // mint-delegate burn_checked - do_process_instruction_dups( - burn_checked( - &program_id, - &account1_key, - &mint_key, - &mint_key, - &[], - 500, - 2, - ) - .unwrap(), - vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], - ) - .unwrap(); - } - - #[test] - fn test_burn() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - let mismatch_key = Pubkey::new_unique(); - let mut mismatch_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint2_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // create new mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create mismatch account - do_process_instruction( - initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut mismatch_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // mint to mismatch account and change mint key - do_process_instruction( - mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut mismatch_account, &mut owner_account], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); - account.mint = mint2_key; - Account::pack(account, &mut mismatch_account.data).unwrap(); - - // missing signer - let mut instruction = - burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap(); - instruction.accounts[1].is_signer = false; - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - instruction, - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account - ], - ) - ); - - // missing owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // account not owned by program - let not_program_id = Pubkey::new_unique(); - account_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - account_account.owner = program_id; - - // mint not owned by program - let not_program_id = Pubkey::new_unique(); - mint_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - mint_account.owner = program_id; - - // mint mismatch - assert_eq!( - Err(TokenError::MintMismatch.into()), - do_process_instruction( - burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(), - vec![&mut mismatch_account, &mut mint_account, &mut owner_account], - ) - ); - - // burn - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 21).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // burn_checked, with incorrect decimals - assert_eq!( - Err(TokenError::MintDecimalsMismatch.into()), - do_process_instruction( - burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // burn_checked - do_process_instruction( - burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 2000 - 42); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42); - - // insufficient funds - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &owner_key, - &[], - 100_000_000 - ) - .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // approve delegate - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 84, - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - .unwrap(); - - // not a delegate of source account - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &owner2_key, // <-- incorrect owner or delegate - &[], - 1, - ) - .unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 85).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account - ], - ) - ); - - // burn via delegate - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account, - ], - ) - .unwrap(); - - // match - let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!(mint.supply, 2000 - 42 - 84); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 1000 - 42 - 84); - - // insufficient funds approved via delegate - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 1).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut delegate_account - ], - ) - ); - } - - #[test] - fn test_burn_and_close_system_and_incinerator_tokens() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let incinerator_account_key = Pubkey::new_unique(); - let mut incinerator_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let system_account_key = Pubkey::new_unique(); - let mut system_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let recipient_key = Pubkey::new_unique(); - let mut recipient_account = SolanaAccount::default(); - let mut mock_incinerator_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - - // create new mint - do_process_instruction( - initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account_account, &mut mint_account], - ) - .unwrap(); - - // create incinerator- and system-owned accounts - do_process_instruction( - initialize_account3( - &program_id, - &incinerator_account_key, - &mint_key, - &solana_program::incinerator::id(), - ) - .unwrap(), - vec![&mut incinerator_account, &mut mint_account], - ) - .unwrap(); - do_process_instruction( - initialize_account3( - &program_id, - &system_account_key, - &mint_key, - &solana_program::system_program::id(), - ) - .unwrap(), - vec![&mut system_account, &mut mint_account], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // transfer half to incinerator, half to system program - do_process_instruction( - transfer( - &program_id, - &account_key, - &incinerator_account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut incinerator_account, - &mut owner_account, - ], - ) - .unwrap(); - do_process_instruction( - transfer( - &program_id, - &account_key, - &system_account_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut system_account, - &mut owner_account, - ], - ) - .unwrap(); - - // close with balance fails - assert_eq!( - Err(TokenError::NonNativeHasBalance.into()), - do_process_instruction( - close_account( - &program_id, - &incinerator_account_key, - &solana_program::incinerator::id(), - &owner_key, - &[] - ) - .unwrap(), - vec![ - &mut incinerator_account, - &mut mock_incinerator_account, - &mut owner_account, - ], - ) - ); - assert_eq!( - Err(TokenError::NonNativeHasBalance.into()), - do_process_instruction( - close_account( - &program_id, - &system_account_key, - &solana_program::incinerator::id(), - &owner_key, - &[] - ) - .unwrap(), - vec![ - &mut system_account, - &mut mock_incinerator_account, - &mut owner_account, - ], - ) - ); - - // anyone can burn - do_process_instruction( - burn( - &program_id, - &incinerator_account_key, - &mint_key, - &recipient_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut incinerator_account, - &mut mint_account, - &mut recipient_account, - ], - ) - .unwrap(); - do_process_instruction( - burn( - &program_id, - &system_account_key, - &mint_key, - &recipient_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut system_account, - &mut mint_account, - &mut recipient_account, - ], - ) - .unwrap(); - - // closing fails if destination is not the incinerator - assert_eq!( - Err(ProgramError::InvalidAccountData), - do_process_instruction( - close_account( - &program_id, - &incinerator_account_key, - &recipient_key, - &owner_key, - &[] - ) - .unwrap(), - vec![ - &mut incinerator_account, - &mut recipient_account, - &mut owner_account, - ], - ) - ); - assert_eq!( - Err(ProgramError::InvalidAccountData), - do_process_instruction( - close_account( - &program_id, - &system_account_key, - &recipient_key, - &owner_key, - &[] - ) - .unwrap(), - vec![ - &mut system_account, - &mut recipient_account, - &mut owner_account, - ], - ) - ); - - // closing succeeds with incinerator recipient - do_process_instruction( - close_account( - &program_id, - &incinerator_account_key, - &solana_program::incinerator::id(), - &owner_key, - &[], - ) - .unwrap(), - vec![ - &mut incinerator_account, - &mut mock_incinerator_account, - &mut owner_account, - ], - ) - .unwrap(); - - do_process_instruction( - close_account( - &program_id, - &system_account_key, - &solana_program::incinerator::id(), - &owner_key, - &[], - ) - .unwrap(), - vec![ - &mut system_account, - &mut mock_incinerator_account, - &mut owner_account, - ], - ) - .unwrap(); - } - - #[test] - fn test_multisig() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = Pubkey::new_unique(); - let mut account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let multisig_key = Pubkey::new_unique(); - let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id); - let multisig_delegate_key = Pubkey::new_unique(); - let mut multisig_delegate_account = SolanaAccount::new( - multisig_minimum_balance(), - Multisig::get_packed_len(), - &program_id, - ); - let signer_keys = vec![Pubkey::new_unique(); MAX_SIGNERS]; - let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().collect(); - let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; - let mut rent_sysvar = rent_sysvar(); - - // multisig is not rent exempt - let account_info_iter = &mut signer_accounts.iter_mut(); - assert_eq!( - Err(TokenError::NotRentExempt.into()), - do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - ], - ) - ); - - multisig_account.lamports = multisig_minimum_balance(); - let mut multisig_account2 = multisig_account.clone(); - - // single signer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![ - &mut multisig_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // single signer using `initialize_multisig2` - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), - vec![&mut multisig_account2, account_info_iter.next().unwrap()], - ) - .unwrap(); - - // multiple signer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - initialize_multisig( - &program_id, - &multisig_delegate_key, - &signer_key_refs, - MAX_SIGNERS as u8, - ) - .unwrap(), - vec![ - &mut multisig_delegate_account, - &mut rent_sysvar, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // create new mint with multisig owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account with multisig owner - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account with multisig owner - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &mint_key, - &multisig_delegate_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut multisig_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &multisig_key, - &[&signer_keys[0]], - 1000, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // approve - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - approve( - &program_id, - &account_key, - &multisig_delegate_key, - &multisig_key, - &[&signer_keys[0]], - 100, - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_delegate_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // transfer - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut account2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // transfer via delegate - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &multisig_delegate_key, - &signer_key_refs, - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut account2_account, - &mut multisig_delegate_account, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // mint to - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // burn - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &multisig_key, - &[&signer_keys[0]], - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // burn via delegate - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - burn( - &program_id, - &account_key, - &mint_key, - &multisig_delegate_key, - &signer_key_refs, - 42, - ) - .unwrap(), - vec![ - &mut account, - &mut mint_account, - &mut multisig_delegate_account, - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // freeze account - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mint2_key = Pubkey::new_unique(); - let mut mint2_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - do_process_instruction( - initialize_mint( - &program_id, - &mint2_key, - &multisig_key, - Some(&multisig_key), - 2, - ) - .unwrap(), - vec![&mut mint2_account, &mut rent_sysvar], - ) - .unwrap(); - do_process_instruction( - initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(), - vec![ - &mut account3_account, - &mut mint2_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - mint_to( - &program_id, - &mint2_key, - &account3_key, - &multisig_key, - &[&signer_keys[0]], - 1000, - ) - .unwrap(), - vec![ - &mut mint2_account, - &mut account3_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - freeze_account( - &program_id, - &account3_key, - &mint2_key, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut account3_account, - &mut mint2_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // do SetAuthority on mint - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - set_authority( - &program_id, - &mint_key, - Some(&owner_key), - AuthorityType::MintTokens, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut mint_account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); - - // do SetAuthority on account - let account_info_iter = &mut signer_accounts.iter_mut(); - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner_key), - AuthorityType::AccountOwner, - &multisig_key, - &[&signer_keys[0]], - ) - .unwrap(), - vec![ - &mut account, - &mut multisig_account, - account_info_iter.next().unwrap(), - ], - ) - .unwrap(); + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, + ]; + assert_eq!(packed, expect); + let unpacked = Multisig::unpack(&packed).unwrap(); + assert_eq!(unpacked, check); } #[test] @@ -5451,1576 +1342,4 @@ mod tests { ); } } - - #[test] - fn test_owner_close_account_dups() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - let to_close_key = Pubkey::new_unique(); - let mut to_close_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let to_close_account_info: AccountInfo = - (&to_close_key, true, &mut to_close_account).into(); - let destination_account_key = Pubkey::new_unique(); - let mut destination_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let destination_account_info: AccountInfo = - (&destination_account_key, true, &mut destination_account).into(); - // create account - do_process_instruction_dups( - initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), - vec![ - to_close_account_info.clone(), - mint_info.clone(), - to_close_account_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // source-owner close - do_process_instruction_dups( - close_account( - &program_id, - &to_close_key, - &destination_account_key, - &to_close_key, - &[], - ) - .unwrap(), - vec![ - to_close_account_info.clone(), - destination_account_info.clone(), - to_close_account_info.clone(), - ], - ) - .unwrap(); - assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); - } - - #[test] - fn test_close_authority_close_account_dups() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - let to_close_key = Pubkey::new_unique(); - let mut to_close_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let to_close_account_info: AccountInfo = - (&to_close_key, true, &mut to_close_account).into(); - let destination_account_key = Pubkey::new_unique(); - let mut destination_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let destination_account_info: AccountInfo = - (&destination_account_key, true, &mut destination_account).into(); - // create account - do_process_instruction_dups( - initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), - vec![ - to_close_account_info.clone(), - mint_info.clone(), - to_close_account_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap(); - account.close_authority = COption::Some(to_close_key); - account.owner = owner_key; - Account::pack(account, &mut to_close_account_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - close_account( - &program_id, - &to_close_key, - &destination_account_key, - &to_close_key, - &[], - ) - .unwrap(), - vec![ - to_close_account_info.clone(), - destination_account_info.clone(), - to_close_account_info.clone(), - ], - ) - .unwrap(); - assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); - } - - #[test] - fn test_close_account() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance() + 42, - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mut rent_sysvar = rent_sysvar(); - - // uninitialized - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - ); - - // initialize and mint to non-native account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 42); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 42); - - // close non-native account with balance - assert_eq!( - Err(TokenError::NonNativeHasBalance.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - ); - assert_eq!(account_account.lamports, account_minimum_balance()); - - // empty account - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - - // wrong owner - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - ); - - // close account - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); - - // fund and initialize new non-native account to test close authority - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - account_account.lamports = 2; - - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::CloseAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // account owner cannot authorize close if close_authority is set - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner_account, - ], - ) - ); - - // close non-native account with close_authority - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); - - // close native account - do_process_instruction( - close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(), - vec![ - &mut account2_account, - &mut account3_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account2_account.data, [0u8; Account::LEN]); - assert_eq!( - account3_account.lamports, - 3 * account_minimum_balance() + 2 + 42 - ); - } - - #[test] - fn test_native_token() { - let program_id = crate::id(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance() + 40, - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account3_key = Pubkey::new_unique(); - let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let owner3_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); - - // initialize native account - do_process_instruction( - initialize_account( - &program_id, - &account2_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); - - // mint_to unsupported - assert_eq!( - Err(TokenError::NativeNotSupported.into()), - do_process_instruction( - mint_to( - &program_id, - &crate::native_mint::id(), - &account_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - ); - - // burn unsupported - let bogus_mint_key = Pubkey::new_unique(); - let mut bogus_mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - do_process_instruction( - initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(), - vec![&mut bogus_mint_account, &mut rent_sysvar], - ) - .unwrap(); - - assert_eq!( - Err(TokenError::NativeNotSupported.into()), - do_process_instruction( - burn( - &program_id, - &account_key, - &bogus_mint_key, - &owner_key, - &[], - 42 - ) - .unwrap(), - vec![ - &mut account_account, - &mut bogus_mint_account, - &mut owner_account - ], - ) - ); - - // ensure can't transfer below rent-exempt reserve - assert_eq!( - Err(TokenError::InsufficientFunds.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 50, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // transfer between native accounts - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 40, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, account_minimum_balance()); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 0); - assert_eq!(account2_account.lamports, account_minimum_balance() + 40); - let account = Account::unpack_unchecked(&account2_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, 40); - - // set close authority - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner3_key), - AuthorityType::CloseAccount, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.close_authority, COption::Some(owner3_key)); - - // set new account owner - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&owner2_key), - AuthorityType::AccountOwner, - &owner_key, - &[], - ) - .unwrap(), - vec![&mut account_account, &mut owner_account], - ) - .unwrap(); - - // close authority cleared - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.close_authority, COption::None); - - // close native account - do_process_instruction( - close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), - vec![ - &mut account_account, - &mut account3_account, - &mut owner2_account, - ], - ) - .unwrap(); - assert_eq!(account_account.lamports, 0); - assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - assert_eq!(account_account.data, [0u8; Account::LEN]); - } - - #[test] - fn test_overflow() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_owner_key = Pubkey::new_unique(); - let mut mint_owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create an account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner2_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint the max to an account - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - u64::MAX, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // attempt to mint one more to account - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - ); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // attempt to mint one more to the other account - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account2_key, - &mint_owner_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account2_account, - &mut mint_owner_account, - ], - ) - ); - - // burn some of the supply - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX - 100); - - do_process_instruction( - mint_to( - &program_id, - &mint_key, - &account_key, - &mint_owner_key, - &[], - 100, - ) - .unwrap(), - vec![ - &mut mint_account, - &mut account_account, - &mut mint_owner_account, - ], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, u64::MAX); - - // manipulate account balance to attempt overflow transfer - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.amount = 1; - Account::pack(account, &mut account2_account.data).unwrap(); - - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner2_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner2_account, - ], - ) - ); - } - - #[test] - fn test_frozen() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account2_key = Pubkey::new_unique(); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint and fund first account - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // create another account - do_process_instruction( - initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account2_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // fund first account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // no transfer if either account is frozen - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account2_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.state = AccountState::Initialized; - Account::pack(account, &mut account_account.data).unwrap(); - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account2_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - transfer( - &program_id, - &account_key, - &account2_key, - &owner_key, - &[], - 500, - ) - .unwrap(), - vec![ - &mut account_account, - &mut account2_account, - &mut owner_account, - ], - ) - ); - - // no approve if account is frozen - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account_account.data).unwrap(); - let delegate_key = Pubkey::new_unique(); - let mut delegate_account = SolanaAccount::default(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - approve( - &program_id, - &account_key, - &delegate_key, - &owner_key, - &[], - 100 - ) - .unwrap(), - vec![ - &mut account_account, - &mut delegate_account, - &mut owner_account, - ], - ) - ); - - // no revoke if account is frozen - let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); - account.delegate = COption::Some(delegate_key); - account.delegated_amount = 100; - Account::pack(account, &mut account_account.data).unwrap(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut owner_account], - ) - ); - - // no set authority if account is frozen - let new_owner_key = Pubkey::new_unique(); - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - set_authority( - &program_id, - &account_key, - Some(&new_owner_key), - AuthorityType::AccountOwner, - &owner_key, - &[] - ) - .unwrap(), - vec![&mut account_account, &mut owner_account,], - ) - ); - - // no mint_to if destination account is frozen - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 100).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account,], - ) - ); - - // no burn if account is frozen - assert_eq!( - Err(TokenError::AccountFrozen.into()), - do_process_instruction( - burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - } - - #[test] - fn test_freeze_thaw_dups() { - let program_id = crate::id(); - let account1_key = Pubkey::new_unique(); - let mut account1_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); - let rent_key = rent::id(); - let mut rent_sysvar = rent_sysvar(); - let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); - - // create mint - do_process_instruction_dups( - initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(), - vec![mint_info.clone(), rent_info.clone()], - ) - .unwrap(); - - // create account - do_process_instruction_dups( - initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - rent_info.clone(), - ], - ) - .unwrap(); - - // freeze where mint freeze_authority is account - do_process_instruction_dups( - freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - - // thaw where mint freeze_authority is account - let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); - account.state = AccountState::Frozen; - Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); - do_process_instruction_dups( - thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), - vec![ - account1_info.clone(), - mint_info.clone(), - account1_info.clone(), - ], - ) - .unwrap(); - } - - #[test] - fn test_freeze_account() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let account_owner_key = Pubkey::new_unique(); - let mut account_owner_account = SolanaAccount::default(); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let owner2_key = Pubkey::new_unique(); - let mut owner2_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create new mint with owner different from account owner - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &account_owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut account_owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // mint to account - do_process_instruction( - mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), - vec![&mut mint_account, &mut account_account, &mut owner_account], - ) - .unwrap(); - - // mint cannot freeze - assert_eq!( - Err(TokenError::MintCannotFreeze.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // missing freeze_authority - let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - mint.freeze_authority = COption::Some(owner_key); - Mint::pack(mint, &mut mint_account.data).unwrap(); - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // check explicit thaw - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // freeze - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Frozen); - - // check explicit freeze - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - ); - - // check thaw authority - assert_eq!( - Err(TokenError::OwnerMismatch.into()), - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner2_account], - ) - ); - - // thaw - do_process_instruction( - thaw_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), - vec![&mut account_account, &mut mint_account, &mut owner_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.state, AccountState::Initialized); - } - - #[test] - fn test_initialize_account2_and_3() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account2_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let mut account3_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - do_process_instruction( - initialize_account2(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account2_account, &mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - assert_eq!(account_account, account2_account); - - do_process_instruction( - initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![&mut account3_account, &mut mint_account], - ) - .unwrap(); - - assert_eq!(account_account, account3_account); - } - - #[test] - fn test_sync_native() { - let program_id = crate::id(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let native_account_key = Pubkey::new_unique(); - let lamports = 40; - let mut native_account = SolanaAccount::new( - account_minimum_balance() + lamports, - Account::get_packed_len(), - &program_id, - ); - let non_native_account_key = Pubkey::new_unique(); - let mut non_native_account = SolanaAccount::new( - account_minimum_balance() + 50, - Account::get_packed_len(), - &program_id, - ); - - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mut rent_sysvar = rent_sysvar(); - - // initialize non-native mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // initialize non-native account - do_process_instruction( - initialize_account(&program_id, &non_native_account_key, &mint_key, &owner_key) - .unwrap(), - vec![ - &mut non_native_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - let account = Account::unpack_unchecked(&non_native_account.data).unwrap(); - assert!(!account.is_native()); - assert_eq!(account.amount, 0); - - // fail sync non-native - assert_eq!( - Err(TokenError::NonNativeNotSupported.into()), - do_process_instruction( - sync_native(&program_id, &non_native_account_key,).unwrap(), - vec![&mut non_native_account], - ) - ); - - // fail sync uninitialized - assert_eq!( - Err(ProgramError::UninitializedAccount), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - - // wrap native account - do_process_instruction( - initialize_account( - &program_id, - &native_account_key, - &crate::native_mint::id(), - &owner_key, - ) - .unwrap(), - vec![ - &mut native_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // fail sync, not owned by program - let not_program_id = Pubkey::new_unique(); - native_account.owner = not_program_id; - assert_eq!( - Err(ProgramError::IncorrectProgramId), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - native_account.owner = program_id; - - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert!(account.is_native()); - assert_eq!(account.amount, lamports); - - // sync, no change - do_process_instruction( - sync_native(&program_id, &native_account_key).unwrap(), - vec![&mut native_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert_eq!(account.amount, lamports); - - // transfer sol - let new_lamports = lamports + 50; - native_account.lamports = account_minimum_balance() + new_lamports; - - // success sync - do_process_instruction( - sync_native(&program_id, &native_account_key).unwrap(), - vec![&mut native_account], - ) - .unwrap(); - let account = Account::unpack_unchecked(&native_account.data).unwrap(); - assert_eq!(account.amount, new_lamports); - - // reduce sol - native_account.lamports -= 1; - - // fail sync - assert_eq!( - Err(TokenError::InvalidState.into()), - do_process_instruction( - sync_native(&program_id, &native_account_key,).unwrap(), - vec![&mut native_account], - ) - ); - } - - #[test] - #[serial] - fn test_get_account_data_size() { - // see integration tests for return-data validity - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mut rent_sysvar = rent_sysvar(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mint_key = Pubkey::new_unique(); - // fail if an invalid mint is passed in - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - get_account_data_size(&program_id, &mint_key).unwrap(), - vec![&mut mint_account], - ) - ); - - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data(Account::LEN.to_le_bytes().to_vec()); - do_process_instruction( - get_account_data_size(&program_id, &mint_key).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - } - - #[test] - fn test_initialize_immutable_owner() { - let program_id = crate::id(); - let account_key = Pubkey::new_unique(); - let mut account_account = SolanaAccount::new( - account_minimum_balance(), - Account::get_packed_len(), - &program_id, - ); - let owner_key = Pubkey::new_unique(); - let mut owner_account = SolanaAccount::default(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - // success initialize immutable - do_process_instruction( - initialize_immutable_owner(&program_id, &account_key).unwrap(), - vec![&mut account_account], - ) - .unwrap(); - - // create account - do_process_instruction( - initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), - vec![ - &mut account_account, - &mut mint_account, - &mut owner_account, - &mut rent_sysvar, - ], - ) - .unwrap(); - - // fail post-init - assert_eq!( - Err(TokenError::AlreadyInUse.into()), - do_process_instruction( - initialize_immutable_owner(&program_id, &account_key).unwrap(), - vec![&mut account_account], - ) - ); - } - - #[test] - #[serial] - fn test_amount_to_ui_amount() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // fail if an invalid mint is passed in - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), - vec![&mut mint_account], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data("0.23".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 23).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("1.1".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("42".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 4200).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data("0".as_bytes().to_vec()); - do_process_instruction( - amount_to_ui_amount(&program_id, &mint_key, 0).unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - } - - #[test] - #[serial] - fn test_ui_amount_to_amount() { - let program_id = crate::id(); - let owner_key = Pubkey::new_unique(); - let mint_key = Pubkey::new_unique(); - let mut mint_account = - SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); - let mut rent_sysvar = rent_sysvar(); - - // fail if an invalid mint is passed in - assert_eq!( - Err(TokenError::InvalidMint.into()), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), - vec![&mut mint_account], - ) - ); - - // create mint - do_process_instruction( - initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar], - ) - .unwrap(); - - set_expected_data(23u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.23").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.20").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.2000").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(20u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, ".20").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(110u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(110u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "1.10").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(4200u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "42").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(4200u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "42.").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - set_expected_data(0u64.to_le_bytes().to_vec()); - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0").unwrap(), - vec![&mut mint_account], - ) - .unwrap(); - - // fail if invalid ui_amount passed in - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, ".").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.111").unwrap(), - vec![&mut mint_account], - ) - ); - assert_eq!( - Err(ProgramError::InvalidArgument), - do_process_instruction( - ui_amount_to_amount(&program_id, &mint_key, "0.t").unwrap(), - vec![&mut mint_account], - ) - ); - } } diff --git a/program/tests/processor.rs b/program/tests/processor.rs new file mode 100644 index 0000000..2d17315 --- /dev/null +++ b/program/tests/processor.rs @@ -0,0 +1,5705 @@ +#![cfg(feature = "test-sbf")] + +use { + serial_test::serial, + solana_program::{ + account_info::IntoAccountInfo, instruction::Instruction, program_error, sysvar::rent, + }, + solana_sdk::{ + account::{ + create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, + }, + account_info::AccountInfo, + entrypoint::ProgramResult, + program_error::ProgramError, + program_option::COption, + program_pack::Pack, + pubkey::Pubkey, + rent::Rent, + }, + spl_token::{ + error::TokenError, + instruction::{ + amount_to_ui_amount, approve, approve_checked, burn, burn_checked, close_account, + freeze_account, get_account_data_size, initialize_account, initialize_account2, + initialize_account3, initialize_immutable_owner, initialize_mint, initialize_mint2, + initialize_multisig, initialize_multisig2, mint_to, mint_to_checked, revoke, + set_authority, sync_native, thaw_account, transfer, transfer_checked, + ui_amount_to_amount, AuthorityType, MAX_SIGNERS, + }, + processor::Processor, + state::{Account, AccountState, Mint, Multisig}, + }, + std::sync::{Arc, RwLock}, +}; + +lazy_static::lazy_static! { + static ref EXPECTED_DATA: Arc>> = Arc::new(RwLock::new(Vec::new())); +} + +fn set_expected_data(expected_data: Vec) { + *EXPECTED_DATA.write().unwrap() = expected_data; +} + +struct SyscallStubs {} +impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs { + fn sol_log(&self, _message: &str) {} + + fn sol_invoke_signed( + &self, + _instruction: &Instruction, + _account_infos: &[AccountInfo], + _signers_seeds: &[&[&[u8]]], + ) -> ProgramResult { + Err(ProgramError::Custom(42)) // Not supported + } + + fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 { + program_error::UNSUPPORTED_SYSVAR + } + + fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 { + program_error::UNSUPPORTED_SYSVAR + } + + #[allow(deprecated)] + fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 { + program_error::UNSUPPORTED_SYSVAR + } + + fn sol_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 { + unsafe { + *(var_addr as *mut _ as *mut Rent) = Rent::default(); + } + solana_program::entrypoint::SUCCESS + } + + fn sol_set_return_data(&self, data: &[u8]) { + assert_eq!(&*EXPECTED_DATA.write().unwrap(), data) + } +} + +fn do_process_instruction( + instruction: Instruction, + accounts: Vec<&mut SolanaAccount>, +) -> ProgramResult { + { + use std::sync::Once; + static ONCE: Once = Once::new(); + + ONCE.call_once(|| { + solana_sdk::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {})); + }); + } + + let mut meta = instruction + .accounts + .iter() + .zip(accounts) + .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) + .collect::>(); + + let account_infos = create_is_signer_account_infos(&mut meta); + Processor::process(&instruction.program_id, &account_infos, &instruction.data) +} + +fn do_process_instruction_dups( + instruction: Instruction, + account_infos: Vec, +) -> ProgramResult { + Processor::process(&instruction.program_id, &account_infos, &instruction.data) +} + +fn rent_sysvar() -> SolanaAccount { + create_account_for_test(&Rent::default()) +} + +fn mint_minimum_balance() -> u64 { + Rent::default().minimum_balance(Mint::get_packed_len()) +} + +fn account_minimum_balance() -> u64 { + Rent::default().minimum_balance(Account::get_packed_len()) +} + +fn multisig_minimum_balance() -> u64 { + Rent::default().minimum_balance(Multisig::get_packed_len()) +} + +#[test] +fn test_initialize_mint() { + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // mint is not rent exempt + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar] + ) + ); + + mint_account.lamports = mint_minimum_balance(); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create twice + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), + vec![&mut mint_account, &mut rent_sysvar] + ) + ); + + // create another mint that can freeze + do_process_instruction( + initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account, &mut rent_sysvar], + ) + .unwrap(); + let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); + assert_eq!(mint.freeze_authority, COption::Some(owner_key)); +} + +#[test] +fn test_initialize_mint2() { + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = SolanaAccount::new(42, Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + + // mint is not rent exempt + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account] + ) + ); + + mint_account.lamports = mint_minimum_balance(); + + // create new mint + do_process_instruction( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // create twice + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), + vec![&mut mint_account] + ) + ); + + // create another mint that can freeze + do_process_instruction( + initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account], + ) + .unwrap(); + let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); + assert_eq!(mint.freeze_authority, COption::Some(owner_key)); +} + +#[test] +fn test_initialize_mint_account() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new(42, Account::get_packed_len(), &program_id); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // account is not rent exempt + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar + ], + ) + ); + + account_account.lamports = account_minimum_balance(); + + // mint is not valid (not initialized) + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar + ], + ) + ); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar + ], + ) + ); + mint_account.owner = program_id; + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create twice + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar + ], + ) + ); +} + +#[test] +fn test_transfer_dups() { + let program_id = spl_token::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_info: AccountInfo = (&account3_key, false, &mut account3_account).into(); + let account4_key = Pubkey::new_unique(); + let mut account4_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account4_info: AccountInfo = (&account4_key, true, &mut account4_account).into(); + let multisig_key = Pubkey::new_unique(); + let mut multisig_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // create another account + do_process_instruction_dups( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + account2_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint to account + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-owner transfer + do_process_instruction_dups( + transfer( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner TransferChecked + do_process_instruction_dups( + transfer_checked( + &program_id, + &account1_key, + &mint_key, + &account2_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-delegate transfer + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.amount = 1000; + account.delegated_amount = 1000; + account.delegate = COption::Some(account1_key); + account.owner = owner_key; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + + do_process_instruction_dups( + transfer( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-delegate TransferChecked + do_process_instruction_dups( + transfer_checked( + &program_id, + &account1_key, + &mint_key, + &account2_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // test destination-owner transfer + do_process_instruction_dups( + initialize_account(&program_id, &account3_key, &mint_key, &account2_key).unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + account2_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], + ) + .unwrap(); + + account1_info.is_signer = false; + account2_info.is_signer = true; + do_process_instruction_dups( + transfer( + &program_id, + &account3_key, + &account2_key, + &account2_key, + &[], + 500, + ) + .unwrap(), + vec![ + account3_info.clone(), + account2_info.clone(), + account2_info.clone(), + ], + ) + .unwrap(); + + // destination-owner TransferChecked + do_process_instruction_dups( + transfer_checked( + &program_id, + &account3_key, + &mint_key, + &account2_key, + &account2_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + account2_info.clone(), + account2_info.clone(), + ], + ) + .unwrap(); + + // test source-multisig signer + do_process_instruction_dups( + initialize_multisig(&program_id, &multisig_key, &[&account4_key], 1).unwrap(), + vec![ + multisig_info.clone(), + rent_info.clone(), + account4_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + initialize_account(&program_id, &account4_key, &mint_key, &multisig_key).unwrap(), + vec![ + account4_info.clone(), + mint_info.clone(), + multisig_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account4_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-multisig-signer transfer + do_process_instruction_dups( + transfer( + &program_id, + &account4_key, + &account2_key, + &multisig_key, + &[&account4_key], + 500, + ) + .unwrap(), + vec![ + account4_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account4_info.clone(), + ], + ) + .unwrap(); + + // source-multisig-signer TransferChecked + do_process_instruction_dups( + transfer_checked( + &program_id, + &account4_key, + &mint_key, + &account2_key, + &multisig_key, + &[&account4_key], + 500, + 2, + ) + .unwrap(), + vec![ + account4_info.clone(), + mint_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account4_info.clone(), + ], + ) + .unwrap(); +} + +#[test] +fn test_transfer() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let mismatch_key = Pubkey::new_unique(); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); + account.mint = mint2_key; + Account::pack(account, &mut mismatch_account.data).unwrap(); + + // mint to account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // missing signer + let mut instruction = transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // mismatch mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &mismatch_key, + &owner_key, + &[], + 1000 + ) + .unwrap(), + vec![ + &mut account_account, + &mut mismatch_account, + &mut owner_account, + ], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner2_key, + &[], + 1000 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // account not owned by program + let not_program_id = Pubkey::new_unique(); + account_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + account_account.owner = program_id; + + // account 2 not owned by program + let not_program_id = Pubkey::new_unique(); + account2_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 0,).unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + account2_account.owner = program_id; + + // transfer + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 1000, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer(&program_id, &account_key, &account2_key, &owner_key, &[], 1).unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // transfer half back + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + transfer_checked( + &program_id, + &account2_key, + &mint_key, + &account_key, + &owner_key, + &[], + 1, + 10 // <-- incorrect decimals + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut account_account, + &mut owner_account, + ], + ) + ); + + // incorrect mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + transfer_checked( + &program_id, + &account2_key, + &account3_key, // <-- incorrect mint + &account_key, + &owner_key, + &[], + 1, + 2 + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account3_account, // <-- incorrect mint + &mut account_account, + &mut owner_account, + ], + ) + ); + // transfer rest with explicit decimals + do_process_instruction( + transfer_checked( + &program_id, + &account2_key, + &mint_key, + &account_key, + &owner_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut account_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer(&program_id, &account2_key, &account_key, &owner_key, &[], 1).unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner_account, + ], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // not a delegate of source account + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner2_key, // <-- incorrect owner or delegate + &[], + 1, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 101 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + + // transfer via delegate + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + .unwrap(); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 1 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); + + // transfer rest + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 900, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // insufficient funds in source account via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &delegate_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut delegate_account, + ], + ) + ); +} + +#[test] +fn test_self_transfer() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let account_info = (&account_key, false, &mut account_account).into_account_info(); + let account3_info = (&account3_key, false, &mut account3_account).into_account_info(); + let delegate_info = (&delegate_key, true, &mut delegate_account).into_account_info(); + let owner_info = (&owner_key, true, &mut owner_account).into_account_info(); + let owner2_info = (&owner2_key, true, &mut owner2_account).into_account_info(); + let mint_info = (&mint_key, false, &mut mint_account).into_account_info(); + + // transfer + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // transfer checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // missing signer + let mut owner_no_sign_info = owner_info.clone(); + let mut instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner_no_sign_info.key, + &[], + 1000, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + owner_no_sign_info.is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_no_sign_info.clone(), + ], + &instruction.data, + ) + ); + + // missing signer checked + let mut instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_no_sign_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + instruction.accounts[3].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_no_sign_info, + ], + &instruction.data, + ) + ); + + // missing owner + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner2_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner2_info.clone(), + ], + &instruction.data, + ) + ); + + // missing owner checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner2_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner2_info.clone(), + ], + &instruction.data, + ) + ); + + // insufficient funds + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner_info.key, + &[], + 1001, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // insufficient funds checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, + &[], + 1001, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // incorrect decimals + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, + &[], + 1, + 10, // <-- incorrect decimals + ) + .unwrap(); + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // incorrect mint + let instruction = transfer_checked( + &program_id, + account_info.key, + account3_info.key, // <-- incorrect mint + account_info.key, + owner_info.key, + &[], + 1, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::MintMismatch.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account3_info.clone(), // <-- incorrect mint + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + + // approve delegate + let instruction = approve( + &program_id, + account_info.key, + delegate_info.key, + owner_info.key, + &[], + 100, + ) + .unwrap(); + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + delegate_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + .unwrap(); + + // delegate transfer + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + delegate_info.key, + &[], + 100, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + assert_eq!(account.delegated_amount, 100); + + // delegate transfer checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + delegate_info.key, + &[], + 100, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + assert_eq!(account.delegated_amount, 100); + + // delegate insufficient funds + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + delegate_info.key, + &[], + 101, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + + // delegate insufficient funds checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + delegate_info.key, + &[], + 101, + 2, + ) + .unwrap(); + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + delegate_info.clone(), + ], + &instruction.data, + ) + ); + + // owner transfer with delegate assigned + let instruction = transfer( + &program_id, + account_info.key, + account_info.key, + owner_info.key, + &[], + 1000, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); + + // owner transfer with delegate assigned checked + let instruction = transfer_checked( + &program_id, + account_info.key, + mint_info.key, + account_info.key, + owner_info.key, + &[], + 1000, + 2, + ) + .unwrap(); + assert_eq!( + Ok(()), + Processor::process( + &instruction.program_id, + &[ + account_info.clone(), + mint_info.clone(), + account_info.clone(), + owner_info.clone(), + ], + &instruction.data, + ) + ); + // no balance change... + let account = Account::unpack_unchecked(&account_info.try_borrow_data().unwrap()).unwrap(); + assert_eq!(account.amount, 1000); +} + +#[test] +fn test_mintable_token_with_zero_supply() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint-able token with zero supply + let decimals = 2; + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!( + mint, + Mint { + mint_authority: COption::Some(owner_key), + supply: 0, + decimals, + is_initialized: true, + freeze_authority: COption::None, + } + ); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + let _ = Mint::unpack(&mint_account.data).unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // mint to 2, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + mint_to_checked( + &program_id, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + decimals + 1 + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + + let _ = Mint::unpack(&mint_account.data).unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // mint to 2 + do_process_instruction( + mint_to_checked( + &program_id, + &mint_key, + &account_key, + &owner_key, + &[], + 42, + decimals, + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + let _ = Mint::unpack(&mint_account.data).unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 84); +} + +#[test] +fn test_approve_dups() { + let program_id = spl_token::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_info: AccountInfo = (&account2_key, false, &mut account2_account).into(); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_info: AccountInfo = (&account3_key, true, &mut account3_account).into(); + let multisig_key = Pubkey::new_unique(); + let mut multisig_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + let multisig_info: AccountInfo = (&multisig_key, true, &mut multisig_account).into(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // create another account + do_process_instruction_dups( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + account2_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint to account + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-owner approve + do_process_instruction_dups( + approve( + &program_id, + &account1_key, + &account2_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner approve_checked + do_process_instruction_dups( + approve_checked( + &program_id, + &account1_key, + &mint_key, + &account2_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account2_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner revoke + do_process_instruction_dups( + revoke(&program_id, &account1_key, &account1_key, &[]).unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); + + // test source-multisig signer + do_process_instruction_dups( + initialize_multisig(&program_id, &multisig_key, &[&account3_key], 1).unwrap(), + vec![ + multisig_info.clone(), + rent_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + initialize_account(&program_id, &account3_key, &mint_key, &multisig_key).unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + multisig_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-multisig-signer approve + do_process_instruction_dups( + approve( + &program_id, + &account3_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + ) + .unwrap(), + vec![ + account3_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + // source-multisig-signer approve_checked + do_process_instruction_dups( + approve_checked( + &program_id, + &account3_key, + &mint_key, + &account2_key, + &multisig_key, + &[&account3_key], + 500, + 2, + ) + .unwrap(), + vec![ + account3_info.clone(), + mint_info.clone(), + account2_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); + + // source-owner multisig-signer + do_process_instruction_dups( + revoke(&program_id, &account3_key, &multisig_key, &[&account3_key]).unwrap(), + vec![ + account3_info.clone(), + multisig_info.clone(), + account3_info.clone(), + ], + ) + .unwrap(); +} + +#[test] +fn test_approve() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // missing signer + let mut instruction = approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // no owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner2_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner2_account, + ], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // approve delegate 2, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + approve_checked( + &program_id, + &account_key, + &mint_key, + &delegate_key, + &owner_key, + &[], + 100, + 0 // <-- incorrect decimals + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // approve delegate 2, with incorrect mint + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + approve_checked( + &program_id, + &account_key, + &account2_key, // <-- bad mint + &delegate_key, + &owner_key, + &[], + 100, + 0 + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, // <-- bad mint + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // approve delegate 2 + do_process_instruction( + approve_checked( + &program_id, + &account_key, + &mint_key, + &delegate_key, + &owner_key, + &[], + 100, + 2, + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // revoke delegate + do_process_instruction( + revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); +} + +#[test] +fn test_set_authority_dups() { + let program_id = spl_token::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // set mint_authority when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::MintTokens, + &mint_key, + &[], + ) + .unwrap(), + vec![mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // set freeze_authority when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::FreezeAccount, + &mint_key, + &[], + ) + .unwrap(), + vec![mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // set account owner when currently self + do_process_instruction_dups( + set_authority( + &program_id, + &account1_key, + Some(&owner_key), + AuthorityType::AccountOwner, + &account1_key, + &[], + ) + .unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); + + // set close_authority when currently self + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.close_authority = COption::Some(account1_key); + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + + do_process_instruction_dups( + set_authority( + &program_id, + &account1_key, + Some(&owner_key), + AuthorityType::CloseAccount, + &account1_key, + &[], + ) + .unwrap(), + vec![account1_info.clone(), account1_info.clone()], + ) + .unwrap(); +} + +#[test] +fn test_set_authority() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let owner3_key = Pubkey::new_unique(); + let mut owner3_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create mint with owner and freeze_authority + do_process_instruction( + initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), + vec![&mut mint2_account, &mut rent_sysvar], + ) + .unwrap(); + + // invalid account + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint2_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner_key), + AuthorityType::AccountOwner, + &owner2_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + ); + + // owner did not sign + let mut instruction = set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],) + ); + + // wrong authority type + assert_eq!( + Err(TokenError::AuthorityTypeNotSupported.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // account owner may not be set to None + assert_eq!( + Err(TokenError::InvalidInstruction.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + None, + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // set delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &owner2_key, + &owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut account_account, + &mut owner2_account, + &mut owner_account, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.delegate, COption::Some(owner2_key)); + assert_eq!(account.delegated_amount, u64::MAX); + + // set owner + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner3_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // check delegate cleared + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.delegate, COption::None); + assert_eq!(account.delegated_amount, 0); + + // set owner without existing delegate + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner3_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner3_account], + ) + .unwrap(); + + // set close_authority + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::CloseAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + .unwrap(); + + // close_authority may be set to None + do_process_instruction( + set_authority( + &program_id, + &account_key, + None, + AuthorityType::CloseAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner2_account], + ) + .unwrap(); + + // wrong owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner3_key), + AuthorityType::MintTokens, + &owner2_key, + &[] + ) + .unwrap(), + vec![&mut mint_account, &mut owner2_account], + ) + ); + + // owner did not sign + let mut instruction = set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],) + ); + + // cannot freeze + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + ); + + // set owner + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + .unwrap(); + + // set owner to None + do_process_instruction( + set_authority( + &program_id, + &mint_key, + None, + AuthorityType::MintTokens, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner2_account], + ) + .unwrap(); + + // test unsetting mint_authority is one-way operation + assert_eq!( + Err(TokenError::FixedSupply.into()), + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::MintTokens, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + ); + + // set freeze_authority + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner_account], + ) + .unwrap(); + + // test unsetting freeze_authority is one-way operation + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + None, + AuthorityType::FreezeAccount, + &owner2_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner2_account], + ) + .unwrap(); + + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + set_authority( + &program_id, + &mint2_key, + Some(&owner2_key), + AuthorityType::FreezeAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint2_account, &mut owner2_account], + ) + ); +} + +#[test] +fn test_mint_to_dups() { + let program_id = spl_token::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &owner_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + owner_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint_to when mint_authority is self + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(), + vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint_to_checked when mint_authority is self + do_process_instruction_dups( + mint_to_checked(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), + vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint_to when mint_authority is account owner + let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow()).unwrap(); + mint.mint_authority = COption::Some(account1_key); + Mint::pack(mint, &mut mint_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + mint_to( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 42, + ) + .unwrap(), + vec![ + mint_info.clone(), + account1_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint_to_checked when mint_authority is account owner + do_process_instruction_dups( + mint_to( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 42, + ) + .unwrap(), + vec![ + mint_info.clone(), + account1_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); +} + +#[test] +fn test_mint_to() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mismatch_key = Pubkey::new_unique(); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let uninitialized_key = Pubkey::new_unique(); + let mut uninitialized_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut rent_sysvar = rent_sysvar(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); + account.mint = mint2_key; + Account::pack(account, &mut mismatch_account.data).unwrap(); + + // mint to + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!(mint.supply, 42); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // mint to another account to test supply accumulation + do_process_instruction( + mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + .unwrap(); + + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!(mint.supply, 84); + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // missing signer + let mut instruction = + mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(); + instruction.accounts[2].is_signer = false; + assert_eq!( + Err(ProgramError::MissingRequiredSignature), + do_process_instruction( + instruction, + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + ); + + // mismatch account + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &account2_key, &owner2_key, &[], 42).unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut owner2_account, + ], + ) + ); + + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + mint_account.owner = program_id; + + // account not owned by program + let not_program_id = Pubkey::new_unique(); + account_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + account_account.owner = program_id; + + // uninitialized destination account + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &uninitialized_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![ + &mut mint_account, + &mut uninitialized_account, + &mut owner_account, + ], + ) + ); + + // unset mint_authority and test minting fails + do_process_instruction( + set_authority( + &program_id, + &mint_key, + None, + AuthorityType::MintTokens, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut mint_account, &mut owner_account], + ) + .unwrap(); + assert_eq!( + Err(TokenError::FixedSupply.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), + vec![&mut mint_account, &mut account2_account, &mut owner_account], + ) + ); +} + +#[test] +fn test_burn_dups() { + let program_id = spl_token::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner_info: AccountInfo = (&owner_key, true, &mut owner_account).into(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // mint to account + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + + // source-owner burn + do_process_instruction_dups( + burn( + &program_id, + &mint_key, + &account1_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-owner burn_checked + do_process_instruction_dups( + burn_checked( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint-owner burn + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.owner = mint_key; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint-owner burn_checked + do_process_instruction_dups( + burn_checked( + &program_id, + &account1_key, + &mint_key, + &mint_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // source-delegate burn + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.delegated_amount = 1000; + account.delegate = COption::Some(account1_key); + account.owner = owner_key; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + burn( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // source-delegate burn_checked + do_process_instruction_dups( + burn_checked( + &program_id, + &account1_key, + &mint_key, + &account1_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // mint-delegate burn + do_process_instruction_dups( + mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), + vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.delegated_amount = 1000; + account.delegate = COption::Some(mint_key); + account.owner = owner_key; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); + + // mint-delegate burn_checked + do_process_instruction_dups( + burn_checked( + &program_id, + &account1_key, + &mint_key, + &mint_key, + &[], + 500, + 2, + ) + .unwrap(), + vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + ) + .unwrap(); +} + +#[test] +fn test_burn() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + let mismatch_key = Pubkey::new_unique(); + let mut mismatch_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint2_key = Pubkey::new_unique(); + let mut rent_sysvar = rent_sysvar(); + + // create new mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create mismatch account + do_process_instruction( + initialize_account(&program_id, &mismatch_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut mismatch_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // mint to mismatch account and change mint key + do_process_instruction( + mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); + account.mint = mint2_key; + Account::pack(account, &mut mismatch_account.data).unwrap(); + + // missing signer + let mut instruction = + burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 42).unwrap(); + instruction.accounts[1].is_signer = false; + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + instruction, + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], + ) + ); + + // missing owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // account not owned by program + let not_program_id = Pubkey::new_unique(); + account_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + account_account.owner = program_id; + + // mint not owned by program + let not_program_id = Pubkey::new_unique(); + mint_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + mint_account.owner = program_id; + + // mint mismatch + assert_eq!( + Err(TokenError::MintMismatch.into()), + do_process_instruction( + burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(), + vec![&mut mismatch_account, &mut mint_account, &mut owner_account], + ) + ); + + // burn + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 21).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // burn_checked, with incorrect decimals + assert_eq!( + Err(TokenError::MintDecimalsMismatch.into()), + do_process_instruction( + burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // burn_checked + do_process_instruction( + burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!(mint.supply, 2000 - 42); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 1000 - 42); + + // insufficient funds + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn( + &program_id, + &account_key, + &mint_key, + &owner_key, + &[], + 100_000_000 + ) + .unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // approve delegate + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 84, + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + .unwrap(); + + // not a delegate of source account + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn( + &program_id, + &account_key, + &mint_key, + &owner2_key, // <-- incorrect owner or delegate + &[], + 1, + ) + .unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 85).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], + ) + ); + + // burn via delegate + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 84).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account, + ], + ) + .unwrap(); + + // match + let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + assert_eq!(mint.supply, 2000 - 42 - 84); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 1000 - 42 - 84); + + // insufficient funds approved via delegate + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &delegate_key, &[], 1).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut delegate_account + ], + ) + ); +} + +#[test] +fn test_burn_and_close_system_and_incinerator_tokens() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let incinerator_account_key = Pubkey::new_unique(); + let mut incinerator_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let system_account_key = Pubkey::new_unique(); + let mut system_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let recipient_key = Pubkey::new_unique(); + let mut recipient_account = SolanaAccount::default(); + let mut mock_incinerator_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + + // create new mint + do_process_instruction( + initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account_account, &mut mint_account], + ) + .unwrap(); + + // create incinerator- and system-owned accounts + do_process_instruction( + initialize_account3( + &program_id, + &incinerator_account_key, + &mint_key, + &solana_program::incinerator::id(), + ) + .unwrap(), + vec![&mut incinerator_account, &mut mint_account], + ) + .unwrap(); + do_process_instruction( + initialize_account3( + &program_id, + &system_account_key, + &mint_key, + &solana_program::system_program::id(), + ) + .unwrap(), + vec![&mut system_account, &mut mint_account], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // transfer half to incinerator, half to system program + do_process_instruction( + transfer( + &program_id, + &account_key, + &incinerator_account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &system_account_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut system_account, + &mut owner_account, + ], + ) + .unwrap(); + + // close with balance fails + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + ); + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut system_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + ); + + // anyone can burn + do_process_instruction( + burn( + &program_id, + &incinerator_account_key, + &mint_key, + &recipient_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mint_account, + &mut recipient_account, + ], + ) + .unwrap(); + do_process_instruction( + burn( + &program_id, + &system_account_key, + &mint_key, + &recipient_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut system_account, + &mut mint_account, + &mut recipient_account, + ], + ) + .unwrap(); + + // closing fails if destination is not the incinerator + assert_eq!( + Err(ProgramError::InvalidAccountData), + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &recipient_key, + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut recipient_account, + &mut owner_account, + ], + ) + ); + assert_eq!( + Err(ProgramError::InvalidAccountData), + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &recipient_key, + &owner_key, + &[] + ) + .unwrap(), + vec![ + &mut system_account, + &mut recipient_account, + &mut owner_account, + ], + ) + ); + + // closing succeeds with incinerator recipient + do_process_instruction( + close_account( + &program_id, + &incinerator_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[], + ) + .unwrap(), + vec![ + &mut incinerator_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); + + do_process_instruction( + close_account( + &program_id, + &system_account_key, + &solana_program::incinerator::id(), + &owner_key, + &[], + ) + .unwrap(), + vec![ + &mut system_account, + &mut mock_incinerator_account, + &mut owner_account, + ], + ) + .unwrap(); +} + +#[test] +fn test_multisig() { + let program_id = spl_token::id(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let account_key = Pubkey::new_unique(); + let mut account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let multisig_key = Pubkey::new_unique(); + let mut multisig_account = SolanaAccount::new(42, Multisig::get_packed_len(), &program_id); + let multisig_delegate_key = Pubkey::new_unique(); + let mut multisig_delegate_account = SolanaAccount::new( + multisig_minimum_balance(), + Multisig::get_packed_len(), + &program_id, + ); + let signer_keys = vec![Pubkey::new_unique(); MAX_SIGNERS]; + let signer_key_refs: Vec<&Pubkey> = signer_keys.iter().collect(); + let mut signer_accounts = vec![SolanaAccount::new(0, 0, &program_id); MAX_SIGNERS]; + let mut rent_sysvar = rent_sysvar(); + + // multisig is not rent exempt + let account_info_iter = &mut signer_accounts.iter_mut(); + assert_eq!( + Err(TokenError::NotRentExempt.into()), + do_process_instruction( + initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account, + &mut rent_sysvar, + account_info_iter.next().unwrap(), + ], + ) + ); + + multisig_account.lamports = multisig_minimum_balance(); + let mut multisig_account2 = multisig_account.clone(); + + // single signer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![ + &mut multisig_account, + &mut rent_sysvar, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // single signer using `initialize_multisig2` + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), + vec![&mut multisig_account2, account_info_iter.next().unwrap()], + ) + .unwrap(); + + // multiple signer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + initialize_multisig( + &program_id, + &multisig_delegate_key, + &signer_key_refs, + MAX_SIGNERS as u8, + ) + .unwrap(), + vec![ + &mut multisig_delegate_account, + &mut rent_sysvar, + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // create new mint with multisig owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account with multisig owner + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &multisig_key).unwrap(), + vec![ + &mut account, + &mut mint_account, + &mut multisig_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account with multisig owner + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &mint_key, + &multisig_delegate_key, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut multisig_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &multisig_key, + &[&signer_keys[0]], + 1000, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // approve + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + approve( + &program_id, + &account_key, + &multisig_delegate_key, + &multisig_key, + &[&signer_keys[0]], + 100, + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_delegate_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // transfer + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut account2_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // transfer via delegate + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &multisig_delegate_key, + &signer_key_refs, + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut account2_account, + &mut multisig_delegate_account, + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // mint to + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // burn + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + burn( + &program_id, + &account_key, + &mint_key, + &multisig_key, + &[&signer_keys[0]], + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut mint_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // burn via delegate + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + burn( + &program_id, + &account_key, + &mint_key, + &multisig_delegate_key, + &signer_key_refs, + 42, + ) + .unwrap(), + vec![ + &mut account, + &mut mint_account, + &mut multisig_delegate_account, + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // freeze account + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mint2_key = Pubkey::new_unique(); + let mut mint2_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + do_process_instruction( + initialize_mint( + &program_id, + &mint2_key, + &multisig_key, + Some(&multisig_key), + 2, + ) + .unwrap(), + vec![&mut mint2_account, &mut rent_sysvar], + ) + .unwrap(); + do_process_instruction( + initialize_account(&program_id, &account3_key, &mint2_key, &owner_key).unwrap(), + vec![ + &mut account3_account, + &mut mint2_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + mint_to( + &program_id, + &mint2_key, + &account3_key, + &multisig_key, + &[&signer_keys[0]], + 1000, + ) + .unwrap(), + vec![ + &mut mint2_account, + &mut account3_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + freeze_account( + &program_id, + &account3_key, + &mint2_key, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut account3_account, + &mut mint2_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // do SetAuthority on mint + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + set_authority( + &program_id, + &mint_key, + Some(&owner_key), + AuthorityType::MintTokens, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut mint_account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); + + // do SetAuthority on account + let account_info_iter = &mut signer_accounts.iter_mut(); + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner_key), + AuthorityType::AccountOwner, + &multisig_key, + &[&signer_keys[0]], + ) + .unwrap(), + vec![ + &mut account, + &mut multisig_account, + account_info_iter.next().unwrap(), + ], + ) + .unwrap(); +} + +#[test] +fn test_owner_close_account_dups() { + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + let to_close_key = Pubkey::new_unique(); + let mut to_close_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let to_close_account_info: AccountInfo = (&to_close_key, true, &mut to_close_account).into(); + let destination_account_key = Pubkey::new_unique(); + let mut destination_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let destination_account_info: AccountInfo = + (&destination_account_key, true, &mut destination_account).into(); + // create account + do_process_instruction_dups( + initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), + vec![ + to_close_account_info.clone(), + mint_info.clone(), + to_close_account_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // source-owner close + do_process_instruction_dups( + close_account( + &program_id, + &to_close_key, + &destination_account_key, + &to_close_key, + &[], + ) + .unwrap(), + vec![ + to_close_account_info.clone(), + destination_account_info.clone(), + to_close_account_info.clone(), + ], + ) + .unwrap(); + assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); +} + +#[test] +fn test_close_authority_close_account_dups() { + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, false, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + let to_close_key = Pubkey::new_unique(); + let mut to_close_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let to_close_account_info: AccountInfo = (&to_close_key, true, &mut to_close_account).into(); + let destination_account_key = Pubkey::new_unique(); + let mut destination_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let destination_account_info: AccountInfo = + (&destination_account_key, true, &mut destination_account).into(); + // create account + do_process_instruction_dups( + initialize_account(&program_id, &to_close_key, &mint_key, &to_close_key).unwrap(), + vec![ + to_close_account_info.clone(), + mint_info.clone(), + to_close_account_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap(); + account.close_authority = COption::Some(to_close_key); + account.owner = owner_key; + Account::pack(account, &mut to_close_account_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + close_account( + &program_id, + &to_close_key, + &destination_account_key, + &to_close_key, + &[], + ) + .unwrap(), + vec![ + to_close_account_info.clone(), + destination_account_info.clone(), + to_close_account_info.clone(), + ], + ) + .unwrap(); + assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); +} + +#[test] +fn test_close_account() { + let program_id = spl_token::id(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance() + 42, + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mut rent_sysvar = rent_sysvar(); + + // uninitialized + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + ); + + // initialize and mint to non-native account + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 42); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &spl_token::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 42); + + // close non-native account with balance + assert_eq!( + Err(TokenError::NonNativeHasBalance.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + ); + assert_eq!(account_account.lamports, account_minimum_balance()); + + // empty account + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + + // wrong owner + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + ); + + // close account + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, 0); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 0); + + // fund and initialize new non-native account to test close authority + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + account_account.lamports = 2; + + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::CloseAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // account owner cannot authorize close if close_authority is set + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner_account, + ], + ) + ); + + // close non-native account with close_authority + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, 0); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, 0); + + // close native account + do_process_instruction( + close_account(&program_id, &account2_key, &account3_key, &owner_key, &[]).unwrap(), + vec![ + &mut account2_account, + &mut account3_account, + &mut owner_account, + ], + ) + .unwrap(); + assert_eq!(account2_account.data, [0u8; Account::LEN]); + assert_eq!( + account3_account.lamports, + 3 * account_minimum_balance() + 2 + 42 + ); +} + +#[test] +fn test_native_token() { + let program_id = spl_token::id(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance() + 40, + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account3_key = Pubkey::new_unique(); + let mut account3_account = SolanaAccount::new(account_minimum_balance(), 0, &program_id); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let owner3_key = Pubkey::new_unique(); + let mut rent_sysvar = rent_sysvar(); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account_key, + &spl_token::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 40); + + // initialize native account + do_process_instruction( + initialize_account( + &program_id, + &account2_key, + &spl_token::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 0); + + // mint_to unsupported + assert_eq!( + Err(TokenError::NativeNotSupported.into()), + do_process_instruction( + mint_to( + &program_id, + &spl_token::native_mint::id(), + &account_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + ); + + // burn unsupported + let bogus_mint_key = Pubkey::new_unique(); + let mut bogus_mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + do_process_instruction( + initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(), + vec![&mut bogus_mint_account, &mut rent_sysvar], + ) + .unwrap(); + + assert_eq!( + Err(TokenError::NativeNotSupported.into()), + do_process_instruction( + burn( + &program_id, + &account_key, + &bogus_mint_key, + &owner_key, + &[], + 42 + ) + .unwrap(), + vec![ + &mut account_account, + &mut bogus_mint_account, + &mut owner_account + ], + ) + ); + + // ensure can't transfer below rent-exempt reserve + assert_eq!( + Err(TokenError::InsufficientFunds.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 50, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // transfer between native accounts + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 40, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, account_minimum_balance()); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 0); + assert_eq!(account2_account.lamports, account_minimum_balance() + 40); + let account = Account::unpack_unchecked(&account2_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, 40); + + // set close authority + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner3_key), + AuthorityType::CloseAccount, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.close_authority, COption::Some(owner3_key)); + + // set new account owner + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&owner2_key), + AuthorityType::AccountOwner, + &owner_key, + &[], + ) + .unwrap(), + vec![&mut account_account, &mut owner_account], + ) + .unwrap(); + + // close authority cleared + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.close_authority, COption::None); + + // close native account + do_process_instruction( + close_account(&program_id, &account_key, &account3_key, &owner2_key, &[]).unwrap(), + vec![ + &mut account_account, + &mut account3_account, + &mut owner2_account, + ], + ) + .unwrap(); + assert_eq!(account_account.lamports, 0); + assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); + assert_eq!(account_account.data, [0u8; Account::LEN]); +} + +#[test] +fn test_overflow() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_owner_key = Pubkey::new_unique(); + let mut mint_owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create new mint with owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create an account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner2_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner2_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint the max to an account + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + u64::MAX, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // attempt to mint one more to account + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + ); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // attempt to mint one more to the other account + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account2_key, + &mint_owner_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account2_account, + &mut mint_owner_account, + ], + ) + ); + + // burn some of the supply + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX - 100); + + do_process_instruction( + mint_to( + &program_id, + &mint_key, + &account_key, + &mint_owner_key, + &[], + 100, + ) + .unwrap(), + vec![ + &mut mint_account, + &mut account_account, + &mut mint_owner_account, + ], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.amount, u64::MAX); + + // manipulate account balance to attempt overflow transfer + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); + account.amount = 1; + Account::pack(account, &mut account2_account.data).unwrap(); + + assert_eq!( + Err(TokenError::Overflow.into()), + do_process_instruction( + transfer( + &program_id, + &account2_key, + &account_key, + &owner2_key, + &[], + 1, + ) + .unwrap(), + vec![ + &mut account2_account, + &mut account_account, + &mut owner2_account, + ], + ) + ); +} + +#[test] +fn test_frozen() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account2_key = Pubkey::new_unique(); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create new mint and fund first account + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // create another account + do_process_instruction( + initialize_account(&program_id, &account2_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account2_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // fund first account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // no transfer if either account is frozen + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); + account.state = AccountState::Frozen; + Account::pack(account, &mut account2_account.data).unwrap(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); + account.state = AccountState::Initialized; + Account::pack(account, &mut account_account.data).unwrap(); + let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); + account.state = AccountState::Frozen; + Account::pack(account, &mut account2_account.data).unwrap(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + transfer( + &program_id, + &account_key, + &account2_key, + &owner_key, + &[], + 500, + ) + .unwrap(), + vec![ + &mut account_account, + &mut account2_account, + &mut owner_account, + ], + ) + ); + + // no approve if account is frozen + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); + account.state = AccountState::Frozen; + Account::pack(account, &mut account_account.data).unwrap(); + let delegate_key = Pubkey::new_unique(); + let mut delegate_account = SolanaAccount::default(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + approve( + &program_id, + &account_key, + &delegate_key, + &owner_key, + &[], + 100 + ) + .unwrap(), + vec![ + &mut account_account, + &mut delegate_account, + &mut owner_account, + ], + ) + ); + + // no revoke if account is frozen + let mut account = Account::unpack_unchecked(&account_account.data).unwrap(); + account.delegate = COption::Some(delegate_key); + account.delegated_amount = 100; + Account::pack(account, &mut account_account.data).unwrap(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut owner_account], + ) + ); + + // no set authority if account is frozen + let new_owner_key = Pubkey::new_unique(); + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + set_authority( + &program_id, + &account_key, + Some(&new_owner_key), + AuthorityType::AccountOwner, + &owner_key, + &[] + ) + .unwrap(), + vec![&mut account_account, &mut owner_account,], + ) + ); + + // no mint_to if destination account is frozen + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 100).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account,], + ) + ); + + // no burn if account is frozen + assert_eq!( + Err(TokenError::AccountFrozen.into()), + do_process_instruction( + burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); +} + +#[test] +fn test_freeze_thaw_dups() { + let program_id = spl_token::id(); + let account1_key = Pubkey::new_unique(); + let mut account1_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account1_info: AccountInfo = (&account1_key, true, &mut account1_account).into(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_info: AccountInfo = (&mint_key, true, &mut mint_account).into(); + let rent_key = rent::id(); + let mut rent_sysvar = rent_sysvar(); + let rent_info: AccountInfo = (&rent_key, false, &mut rent_sysvar).into(); + + // create mint + do_process_instruction_dups( + initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(), + vec![mint_info.clone(), rent_info.clone()], + ) + .unwrap(); + + // create account + do_process_instruction_dups( + initialize_account(&program_id, &account1_key, &mint_key, &account1_key).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + rent_info.clone(), + ], + ) + .unwrap(); + + // freeze where mint freeze_authority is account + do_process_instruction_dups( + freeze_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); + + // thaw where mint freeze_authority is account + let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); + account.state = AccountState::Frozen; + Account::pack(account, &mut account1_info.data.borrow_mut()).unwrap(); + do_process_instruction_dups( + thaw_account(&program_id, &account1_key, &mint_key, &account1_key, &[]).unwrap(), + vec![ + account1_info.clone(), + mint_info.clone(), + account1_info.clone(), + ], + ) + .unwrap(); +} + +#[test] +fn test_freeze_account() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let account_owner_key = Pubkey::new_unique(); + let mut account_owner_account = SolanaAccount::default(); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let owner2_key = Pubkey::new_unique(); + let mut owner2_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create new mint with owner different from account owner + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &account_owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut account_owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // mint to account + do_process_instruction( + mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), + vec![&mut mint_account, &mut account_account, &mut owner_account], + ) + .unwrap(); + + // mint cannot freeze + assert_eq!( + Err(TokenError::MintCannotFreeze.into()), + do_process_instruction( + freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // missing freeze_authority + let mut mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); + mint.freeze_authority = COption::Some(owner_key); + Mint::pack(mint, &mut mint_account.data).unwrap(); + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + freeze_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // check explicit thaw + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // freeze + do_process_instruction( + freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.state, AccountState::Frozen); + + // check explicit freeze + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + ); + + // check thaw authority + assert_eq!( + Err(TokenError::OwnerMismatch.into()), + do_process_instruction( + thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner2_account], + ) + ); + + // thaw + do_process_instruction( + thaw_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), + vec![&mut account_account, &mut mint_account, &mut owner_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&account_account.data).unwrap(); + assert_eq!(account.state, AccountState::Initialized); +} + +#[test] +fn test_initialize_account2_and_3() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account2_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let mut account3_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + do_process_instruction( + initialize_account2(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account2_account, &mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + assert_eq!(account_account, account2_account); + + do_process_instruction( + initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![&mut account3_account, &mut mint_account], + ) + .unwrap(); + + assert_eq!(account_account, account3_account); +} + +#[test] +fn test_sync_native() { + let program_id = spl_token::id(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let native_account_key = Pubkey::new_unique(); + let lamports = 40; + let mut native_account = SolanaAccount::new( + account_minimum_balance() + lamports, + Account::get_packed_len(), + &program_id, + ); + let non_native_account_key = Pubkey::new_unique(); + let mut non_native_account = SolanaAccount::new( + account_minimum_balance() + 50, + Account::get_packed_len(), + &program_id, + ); + + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mut rent_sysvar = rent_sysvar(); + + // initialize non-native mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // initialize non-native account + do_process_instruction( + initialize_account(&program_id, &non_native_account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut non_native_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + let account = Account::unpack_unchecked(&non_native_account.data).unwrap(); + assert!(!account.is_native()); + assert_eq!(account.amount, 0); + + // fail sync non-native + assert_eq!( + Err(TokenError::NonNativeNotSupported.into()), + do_process_instruction( + sync_native(&program_id, &non_native_account_key,).unwrap(), + vec![&mut non_native_account], + ) + ); + + // fail sync uninitialized + assert_eq!( + Err(ProgramError::UninitializedAccount), + do_process_instruction( + sync_native(&program_id, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); + + // wrap native account + do_process_instruction( + initialize_account( + &program_id, + &native_account_key, + &spl_token::native_mint::id(), + &owner_key, + ) + .unwrap(), + vec![ + &mut native_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // fail sync, not owned by program + let not_program_id = Pubkey::new_unique(); + native_account.owner = not_program_id; + assert_eq!( + Err(ProgramError::IncorrectProgramId), + do_process_instruction( + sync_native(&program_id, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); + native_account.owner = program_id; + + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert!(account.is_native()); + assert_eq!(account.amount, lamports); + + // sync, no change + do_process_instruction( + sync_native(&program_id, &native_account_key).unwrap(), + vec![&mut native_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert_eq!(account.amount, lamports); + + // transfer sol + let new_lamports = lamports + 50; + native_account.lamports = account_minimum_balance() + new_lamports; + + // success sync + do_process_instruction( + sync_native(&program_id, &native_account_key).unwrap(), + vec![&mut native_account], + ) + .unwrap(); + let account = Account::unpack_unchecked(&native_account.data).unwrap(); + assert_eq!(account.amount, new_lamports); + + // reduce sol + native_account.lamports -= 1; + + // fail sync + assert_eq!( + Err(TokenError::InvalidState.into()), + do_process_instruction( + sync_native(&program_id, &native_account_key,).unwrap(), + vec![&mut native_account], + ) + ); +} + +#[test] +#[serial] +fn test_get_account_data_size() { + // see integration tests for return-data validity + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mut rent_sysvar = rent_sysvar(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mint_key = Pubkey::new_unique(); + // fail if an invalid mint is passed in + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + get_account_data_size(&program_id, &mint_key).unwrap(), + vec![&mut mint_account], + ) + ); + + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data(Account::LEN.to_le_bytes().to_vec()); + do_process_instruction( + get_account_data_size(&program_id, &mint_key).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); +} + +#[test] +fn test_initialize_immutable_owner() { + let program_id = spl_token::id(); + let account_key = Pubkey::new_unique(); + let mut account_account = SolanaAccount::new( + account_minimum_balance(), + Account::get_packed_len(), + &program_id, + ); + let owner_key = Pubkey::new_unique(); + let mut owner_account = SolanaAccount::default(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + // success initialize immutable + do_process_instruction( + initialize_immutable_owner(&program_id, &account_key).unwrap(), + vec![&mut account_account], + ) + .unwrap(); + + // create account + do_process_instruction( + initialize_account(&program_id, &account_key, &mint_key, &owner_key).unwrap(), + vec![ + &mut account_account, + &mut mint_account, + &mut owner_account, + &mut rent_sysvar, + ], + ) + .unwrap(); + + // fail post-init + assert_eq!( + Err(TokenError::AlreadyInUse.into()), + do_process_instruction( + initialize_immutable_owner(&program_id, &account_key).unwrap(), + vec![&mut account_account], + ) + ); +} + +#[test] +#[serial] +fn test_amount_to_ui_amount() { + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // fail if an invalid mint is passed in + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), + vec![&mut mint_account], + ) + ); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data("0.23".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 23).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("1.1".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("42".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 4200).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data("0".as_bytes().to_vec()); + do_process_instruction( + amount_to_ui_amount(&program_id, &mint_key, 0).unwrap(), + vec![&mut mint_account], + ) + .unwrap(); +} + +#[test] +#[serial] +fn test_ui_amount_to_amount() { + let program_id = spl_token::id(); + let owner_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let mut mint_account = + SolanaAccount::new(mint_minimum_balance(), Mint::get_packed_len(), &program_id); + let mut rent_sysvar = rent_sysvar(); + + // fail if an invalid mint is passed in + assert_eq!( + Err(TokenError::InvalidMint.into()), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), + vec![&mut mint_account], + ) + ); + + // create mint + do_process_instruction( + initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), + vec![&mut mint_account, &mut rent_sysvar], + ) + .unwrap(); + + set_expected_data(23u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.23").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.20").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.2000").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(20u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, ".20").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(110u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(110u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "1.10").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(4200u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "42").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(4200u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "42.").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + set_expected_data(0u64.to_le_bytes().to_vec()); + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0").unwrap(), + vec![&mut mint_account], + ) + .unwrap(); + + // fail if invalid ui_amount passed in + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, ".").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.111").unwrap(), + vec![&mut mint_account], + ) + ); + assert_eq!( + Err(ProgramError::InvalidArgument), + do_process_instruction( + ui_amount_to_amount(&program_id, &mint_key, "0.t").unwrap(), + vec![&mut mint_account], + ) + ); +} From eab98d40f5feb5cebca35814488d88adefe28cf9 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Thu, 16 Jan 2025 12:30:09 +0000 Subject: [PATCH 261/335] tests: Use mollusk on process instruction (#18) * Use mollusk on process instruction * Enable workflow * Use non-chain process instruction * Address review comments --- .github/workflows/main.yml | 1 - program/tests/processor.rs | 283 +++++++++++++++++++------------------ 2 files changed, 142 insertions(+), 142 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 46166f3..1a90eed 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,6 @@ on: push: branches: [main] pull_request: - branches: [main] jobs: format_and_lint_client_js: diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 2d17315..32e0779 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -1,21 +1,23 @@ #![cfg(feature = "test-sbf")] +//! Program state processor tests + use { + mollusk_svm::Mollusk, serial_test::serial, - solana_program::{ - account_info::IntoAccountInfo, instruction::Instruction, program_error, sysvar::rent, - }, solana_sdk::{ account::{ - create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount, + create_account_for_test, Account as SolanaAccount, AccountSharedData, ReadableAccount, }, - account_info::AccountInfo, + account_info::{AccountInfo, IntoAccountInfo}, entrypoint::ProgramResult, + instruction::Instruction, program_error::ProgramError, program_option::COption, program_pack::Pack, pubkey::Pubkey, rent::Rent, + sysvar::rent, }, spl_token::{ error::TokenError, @@ -27,87 +29,105 @@ use { set_authority, sync_native, thaw_account, transfer, transfer_checked, ui_amount_to_amount, AuthorityType, MAX_SIGNERS, }, - processor::Processor, state::{Account, AccountState, Mint, Multisig}, }, - std::sync::{Arc, RwLock}, + std::{ + collections::HashMap, + sync::{Arc, RwLock}, + }, }; lazy_static::lazy_static! { static ref EXPECTED_DATA: Arc>> = Arc::new(RwLock::new(Vec::new())); } -fn set_expected_data(expected_data: Vec) { - *EXPECTED_DATA.write().unwrap() = expected_data; -} - -struct SyscallStubs {} -impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs { - fn sol_log(&self, _message: &str) {} - - fn sol_invoke_signed( - &self, - _instruction: &Instruction, - _account_infos: &[AccountInfo], - _signers_seeds: &[&[&[u8]]], - ) -> ProgramResult { - Err(ProgramError::Custom(42)) // Not supported - } - - fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - #[allow(deprecated)] - fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 { - program_error::UNSUPPORTED_SYSVAR - } - - fn sol_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 { - unsafe { - *(var_addr as *mut _ as *mut Rent) = Rent::default(); - } - solana_program::entrypoint::SUCCESS - } - - fn sol_set_return_data(&self, data: &[u8]) { - assert_eq!(&*EXPECTED_DATA.write().unwrap(), data) - } -} - fn do_process_instruction( instruction: Instruction, - accounts: Vec<&mut SolanaAccount>, + mut accounts: Vec<&mut SolanaAccount>, ) -> ProgramResult { - { - use std::sync::Once; - static ONCE: Once = Once::new(); - - ONCE.call_once(|| { - solana_sdk::program_stubs::set_syscall_stubs(Box::new(SyscallStubs {})); - }); - } - - let mut meta = instruction + // Prepare accounts for mollusk. + let instruction_accounts: Vec<(Pubkey, AccountSharedData)> = instruction .accounts .iter() - .zip(accounts) - .map(|(account_meta, account)| (&account_meta.pubkey, account_meta.is_signer, account)) - .collect::>(); + .zip(&accounts) + .map(|(account_meta, account)| { + ( + account_meta.pubkey, + AccountSharedData::from((*account).clone()), + ) + }) + .collect(); + + let mollusk = Mollusk::new(&spl_token::ID, "spl_token"); + let result = mollusk.process_instruction(&instruction, &instruction_accounts); - let account_infos = create_is_signer_account_infos(&mut meta); - Processor::process(&instruction.program_id, &account_infos, &instruction.data) + // Update accounts after the instruction is processed. + for (original, (_, updated)) in accounts + .iter_mut() + .zip(result.resulting_accounts.into_iter()) + { + original.data = updated.data().to_vec(); + original.lamports = updated.lamports(); + original.owner = *updated.owner(); + } + + result + .raw_result + .map_err(|e| ProgramError::try_from(e).unwrap()) } fn do_process_instruction_dups( instruction: Instruction, account_infos: Vec, ) -> ProgramResult { - Processor::process(&instruction.program_id, &account_infos, &instruction.data) + let mut cached_accounts = HashMap::new(); + let mut dedup_accounts = Vec::new(); + + // Dedup accounts for mollusk. + account_infos.iter().for_each(|account_info| { + if !cached_accounts.contains_key(account_info.key) { + let account = SolanaAccount { + lamports: account_info.lamports(), + data: account_info.try_borrow_data().unwrap().to_vec(), + owner: *account_info.owner, + executable: account_info.executable, + rent_epoch: account_info.rent_epoch, + }; + dedup_accounts.push((*account_info.key, AccountSharedData::from(account))); + cached_accounts.insert(account_info.key, account_info); + } + }); + + let mollusk = Mollusk::new(&spl_token::ID, "spl_token"); + let result = mollusk.process_instruction(&instruction, &dedup_accounts); + + // Update accounts after the instruction is processed. + result + .resulting_accounts + .into_iter() + .for_each(|(pubkey, account)| { + let account_info = cached_accounts.get(&pubkey).unwrap(); + if account.data().is_empty() { + // When the account is closed, the tests expect the data to + // be zeroed. + account_info.try_borrow_mut_data().unwrap().fill(0); + } else { + account_info + .try_borrow_mut_data() + .unwrap() + .copy_from_slice(account.data()); + } + **account_info.try_borrow_mut_lamports().unwrap() = account.lamports(); + account_info.assign(account.owner()); + }); + + result + .raw_result + .map_err(|e| ProgramError::try_from(e).unwrap()) +} + +fn set_expected_data(expected_data: Vec) { + *EXPECTED_DATA.write().unwrap() = expected_data; } fn rent_sysvar() -> SolanaAccount { @@ -1217,14 +1237,13 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Ok(()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), account_info.clone(), owner_info.clone(), ], - &instruction.data, ) ); // no balance change... @@ -1245,15 +1264,14 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Ok(()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), mint_info.clone(), account_info.clone(), owner_info.clone(), ], - &instruction.data, ) ); // no balance change... @@ -1275,14 +1293,13 @@ fn test_self_transfer() { owner_no_sign_info.is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), account_info.clone(), owner_no_sign_info.clone(), ], - &instruction.data, ) ); @@ -1301,15 +1318,14 @@ fn test_self_transfer() { instruction.accounts[3].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), mint_info.clone(), account_info.clone(), owner_no_sign_info, ], - &instruction.data, ) ); @@ -1325,14 +1341,13 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), account_info.clone(), owner2_info.clone(), ], - &instruction.data, ) ); @@ -1350,15 +1365,14 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Err(TokenError::OwnerMismatch.into()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), mint_info.clone(), account_info.clone(), owner2_info.clone(), ], - &instruction.data, ) ); @@ -1374,14 +1388,13 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), account_info.clone(), owner_info.clone(), ], - &instruction.data, ) ); @@ -1399,15 +1412,14 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), mint_info.clone(), account_info.clone(), owner_info.clone(), ], - &instruction.data, ) ); @@ -1425,15 +1437,14 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Err(TokenError::MintDecimalsMismatch.into()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), mint_info.clone(), account_info.clone(), owner_info.clone(), ], - &instruction.data, ) ); @@ -1451,15 +1462,14 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Err(TokenError::MintMismatch.into()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), account3_info.clone(), // <-- incorrect mint account_info.clone(), owner_info.clone(), ], - &instruction.data, ) ); @@ -1473,14 +1483,13 @@ fn test_self_transfer() { 100, ) .unwrap(); - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), delegate_info.clone(), owner_info.clone(), ], - &instruction.data, ) .unwrap(); @@ -1496,14 +1505,13 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Ok(()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), account_info.clone(), delegate_info.clone(), ], - &instruction.data, ) ); // no balance change... @@ -1525,15 +1533,14 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Ok(()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), mint_info.clone(), account_info.clone(), delegate_info.clone(), ], - &instruction.data, ) ); // no balance change... @@ -1553,14 +1560,13 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), account_info.clone(), delegate_info.clone(), ], - &instruction.data, ) ); @@ -1578,15 +1584,14 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Err(TokenError::InsufficientFunds.into()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), mint_info.clone(), account_info.clone(), delegate_info.clone(), ], - &instruction.data, ) ); @@ -1602,14 +1607,13 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Ok(()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), account_info.clone(), owner_info.clone(), ], - &instruction.data, ) ); // no balance change... @@ -1630,15 +1634,14 @@ fn test_self_transfer() { .unwrap(); assert_eq!( Ok(()), - Processor::process( - &instruction.program_id, - &[ + do_process_instruction_dups( + instruction, + vec![ account_info.clone(), mint_info.clone(), account_info.clone(), owner_info.clone(), ], - &instruction.data, ) ); // no balance change... @@ -3020,8 +3023,8 @@ fn test_burn_dups() { do_process_instruction_dups( burn( &program_id, - &mint_key, &account1_key, + &mint_key, &account1_key, &[], 500, @@ -4406,10 +4409,9 @@ fn test_close_account() { ], ) .unwrap(); + assert!(account_account.data.is_empty()); assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); // fund and initialize new non-native account to test close authority let account_key = Pubkey::new_unique(); @@ -4473,10 +4475,9 @@ fn test_close_account() { ], ) .unwrap(); + assert!(account_account.data.is_empty()); assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance() + 2); - let account = Account::unpack_unchecked(&account_account.data).unwrap(); - assert_eq!(account.amount, 0); // close native account do_process_instruction( @@ -4488,7 +4489,7 @@ fn test_close_account() { ], ) .unwrap(); - assert_eq!(account2_account.data, [0u8; Account::LEN]); + assert!(account2_account.data.is_empty()); assert_eq!( account3_account.lamports, 3 * account_minimum_balance() + 2 + 42 @@ -4706,7 +4707,7 @@ fn test_native_token() { .unwrap(); assert_eq!(account_account.lamports, 0); assert_eq!(account3_account.lamports, 2 * account_minimum_balance()); - assert_eq!(account_account.data, [0u8; Account::LEN]); + assert!(account_account.data.is_empty()); } #[test] From 8fe3789d1dc3fdf849886e4c5a0db7bebaa86f63 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Thu, 16 Jan 2025 13:28:13 +0000 Subject: [PATCH 262/335] tests: Add process instruction checks (#19) * Add process instruction checks * Update mollusk git reference * Add missing check * Add return data checks --- Cargo.lock | 568 ++++++++++------- program/Cargo.toml | 2 +- program/tests/assert_instruction_count.rs | 16 +- program/tests/close_account.rs | 102 ++-- program/tests/processor.rs | 714 ++++++++++++++++++++-- program/tests/setup.rs | 17 +- 6 files changed, 1069 insertions(+), 350 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48b0c96..80c8a52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -284,9 +284,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" dependencies = [ "serde", ] @@ -335,11 +335,11 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" +checksum = "9fb65153674e51d3a42c8f27b05b9508cea85edfaade8aa46bc8fc18cecdfef3" dependencies = [ - "borsh-derive 1.5.3", + "borsh-derive 1.5.4", "cfg_aliases", ] @@ -358,15 +358,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" +checksum = "a396e17ad94059c650db3d253bb6e25927f1eb462eede7e7a153bb6e75dce0a7" dependencies = [ "once_cell", "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -439,22 +439,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.20.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -471,9 +471,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.2.4" +version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" dependencies = [ "shlex", ] @@ -498,7 +498,7 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -663,7 +663,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -687,7 +687,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -698,7 +698,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -746,7 +746,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -822,7 +822,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -903,6 +903,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1317,7 +1332,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -1389,9 +1404,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -1414,9 +1429,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libsecp256k1" @@ -1480,9 +1495,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" @@ -1502,9 +1517,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" @@ -1538,9 +1553,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] @@ -1559,8 +1574,7 @@ dependencies = [ [[package]] name = "mollusk-svm" version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceaf67fe3f95a9478f4f5b0d71e77c073eee7a795a74d6143317a22454c289" +source = "git+https://github.com/buffalojoec/mollusk.git#ba391d116e8a032806cb093e7433940fa2cf27b6" dependencies = [ "bincode", "mollusk-svm-error", @@ -1577,8 +1591,7 @@ dependencies = [ [[package]] name = "mollusk-svm-error" version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8738bc85a52d123012209a573f17faffa1db440493396ae2e1f64fbb8f3579bf" +source = "git+https://github.com/buffalojoec/mollusk.git#ba391d116e8a032806cb093e7433940fa2cf27b6" dependencies = [ "solana-sdk", "thiserror 1.0.69", @@ -1587,8 +1600,7 @@ dependencies = [ [[package]] name = "mollusk-svm-keys" version = "0.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a7656d86d743de0a9788ce4c0e9ff63028a42e350131ebe67c476cdde6ac9f" +source = "git+https://github.com/buffalojoec/mollusk.git#ba391d116e8a032806cb093e7433940fa2cf27b6" dependencies = [ "mollusk-svm-error", "solana-sdk", @@ -1647,7 +1659,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -1709,14 +1721,14 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -1733,6 +1745,44 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags 2.8.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1788,9 +1838,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1798,6 +1848,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1827,9 +1883,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -1842,7 +1898,7 @@ checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.6.0", + "bitflags 2.8.0", "lazy_static", "num-traits", "rand 0.8.5", @@ -1871,9 +1927,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1964,7 +2020,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", ] [[package]] @@ -2071,11 +2127,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", @@ -2113,6 +2169,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "rusty-fork" version = "0.3.0" @@ -2133,9 +2195,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scc" -version = "2.2.6" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b13f8ea6177672c49d12ed964cca44836f59621981b04a3e26b87e675181de" +checksum = "28e1c91382686d21b5ac7959341fcb9780fa7c03773646995a87c950fa7be640" dependencies = [ "sdd", ] @@ -2176,9 +2238,9 @@ checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] @@ -2194,20 +2256,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa", "memchr", @@ -2229,9 +2291,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "serde", "serde_derive", @@ -2240,14 +2302,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -2272,7 +2334,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -2354,9 +2416,9 @@ dependencies = [ [[package]] name = "solana-account" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730219420b206253977b8cc8fd7846ffe021ab2e2c718e70db420efbd2775547" +checksum = "5fb7cd6b50247886f9ef190d14896c85a4337fe0e648a9aba162a0b2d283cae2" dependencies = [ "bincode", "serde", @@ -2368,9 +2430,9 @@ dependencies = [ [[package]] name = "solana-account-info" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6abe81cfc4a75f71a510c6856b03a7d8525e416af3c69d55daef62e6078b8d40" +checksum = "e053b991f91fd274df53e070c77a0a6a33681a5102c6421a0ca9ffaa0040368a" dependencies = [ "bincode", "serde", @@ -2381,18 +2443,18 @@ dependencies = [ [[package]] name = "solana-atomic-u64" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391b795afcdcad39ddc6c938d64b789d036cdfe00d9dc5ff83024cf2da9f066f" +checksum = "966dce88672728380c476d5d3e54c02025875100b8246db05669961806c9575e" dependencies = [ "parking_lot", ] [[package]] name = "solana-bincode" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e85cb5961c356345a61378163fd9057011b35540f8bcdd8d8a09cb10117264f" +checksum = "c117b9646b1e9e6c4b48f363ad4c5af25c4ab35754ff307714e5fec2c3c4bb6b" dependencies = [ "bincode", "serde", @@ -2401,9 +2463,9 @@ dependencies = [ [[package]] name = "solana-bn254" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39c4030db26ad618f7e18fb5284df19fd52a68e092a1ca58db857108c4cc777" +checksum = "12227c0e89785367be826b51452807c36f31c4f25cf8891da259b699e0de882d" dependencies = [ "ark-bn254", "ark-ec", @@ -2416,19 +2478,19 @@ dependencies = [ [[package]] name = "solana-borsh" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d526f3525ab22a3ada3f9a1d642664dafac00dc9208326b701a2045514eb04" +checksum = "7c55b83c305eac62095b6f24ea2ae729f17de47e5a4e866ee4ddd0dc501b351e" dependencies = [ "borsh 0.10.4", - "borsh 1.5.3", + "borsh 1.5.4", ] [[package]] name = "solana-bpf-loader-program" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142e0407f8428a1d2a33154d1d3d1c134ad257651ddff0811c17a6ee840def36" +checksum = "bd37acbbdf0c188f74031a144b233f266ed124f3e45c2d24578b1fd5e14a62bb" dependencies = [ "bincode", "byteorder", @@ -2453,29 +2515,30 @@ dependencies = [ [[package]] name = "solana-clock" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7848171e53fa528efd41dd4b3ab919f47b851f8bb4a827d63ff95678f08737fc" +checksum = "a2387b936492cab0649c2a3e3fcfb282077029b533fa8454c88c41dff3bc2552" dependencies = [ "serde", "serde_derive", "solana-sdk-macro", + "solana-sysvar-id", ] [[package]] name = "solana-compute-budget" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebf2f023f471bd1195b7f420e13ffc2422592dd48e71104b4901300b49ac493e" +checksum = "91c3a791445139e208e83fde5ddfcbde462f7b90bd21fe8888b8f7d7863af9af" dependencies = [ "solana-sdk", ] [[package]] name = "solana-cpi" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25c536ad0ce25d84a64f48dedcb773e764827e0ef781eda41fa1fa35f5d64b38" +checksum = "00bae0591481827ac9cfce5573aad2918bb01f91289b811ea531df4fcb73d136" dependencies = [ "solana-account-info", "solana-define-syscall", @@ -2487,9 +2550,9 @@ dependencies = [ [[package]] name = "solana-curve25519" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f934d38b6f2a940fb1e1d8eaa17a14ffd3773b37be9fb29fa4bcec1bac5e4591" +checksum = "07ec1e9b0cf73334da62f82ac9c19985f18410c2e59f020c0e4a8cf18d1607ef" dependencies = [ "bytemuck", "bytemuck_derive", @@ -2500,24 +2563,24 @@ dependencies = [ [[package]] name = "solana-decode-error" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a431f532d030098e81d120877f2dddbd3dd90bea5b259198a6aae4ff6456c3" +checksum = "8880dc18fb97c6205214d1f3ce2f1152e997ecc6f6da4bb458fbf6e6207a0693" dependencies = [ "num-traits", ] [[package]] name = "solana-define-syscall" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7062ae1de58e294d3bee5fd2c89efc155b7f7383ddce4cb88345dfafaaabc5bd" +checksum = "6452c4a8fc77cc60ad2934b19f2d75691067f17355b34462d52285395c1c99db" [[package]] name = "solana-derivation-path" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12080d9bf8eecd559c6f40b5aaf9e47f7f28f515218087f83f02e493b46d8388" +checksum = "a03d1149b531c0740a96f36445eec5a937f364729515c924808c40c3706b3b55" dependencies = [ "derivation-path", "qstring", @@ -2526,20 +2589,21 @@ dependencies = [ [[package]] name = "solana-epoch-schedule" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65c4cf7d7c266d353169cf4feeada5e4bba3a55f33715535fa1ef49080eac3e0" +checksum = "6e783a735416c534228f24f18f18ade0b189c2c8a93be486c9a26bd314517d93" dependencies = [ "serde", "serde_derive", "solana-sdk-macro", + "solana-sysvar-id", ] [[package]] name = "solana-feature-set" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cebf45992982065a0b01b4e109bf039b2ebf6394b21672382fd951516d4c9b0" +checksum = "cb12f174930110d90589281795fd17e03389e22170461a4d528212865e13c621" dependencies = [ "lazy_static", "solana-clock", @@ -2551,9 +2615,9 @@ dependencies = [ [[package]] name = "solana-fee-calculator" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2befe056ece2eb5807298c2b569a35ee52f79df859bdd16a1f97869f8224a28" +checksum = "e1fa18582732d94369263c42eeee967ff919e99b9b15ba747fb7534aa24fbbc0" dependencies = [ "log", "serde", @@ -2562,11 +2626,11 @@ dependencies = [ [[package]] name = "solana-hash" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1807bc4e9e1d25271514167d5a1e698ce5a330bce547a368242dd63b355b5faa" +checksum = "58e35f984e3d60a58184743446250cf724afb34ed65f794da0dc4b462f9c1929" dependencies = [ - "borsh 1.5.3", + "borsh 1.5.4", "bs58", "bytemuck", "bytemuck_derive", @@ -2580,9 +2644,9 @@ dependencies = [ [[package]] name = "solana-inflation" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60b572cdf0ec8fcf5a53e5ba4e3e19814dd96c2b9c156d5828be68d0d2e7103" +checksum = "072f2f3562b4a77a1873250e9e6239389887114ed28846c1174e68979ce021a8" dependencies = [ "serde", "serde_derive", @@ -2590,12 +2654,12 @@ dependencies = [ [[package]] name = "solana-instruction" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfef689e06e5c7cb6206d4dc61ac77733de4f72d754e0d531393206abc27dbe4" +checksum = "35fc69f7f75df0b11e99c03393b24a7443aec0430518054de14715c59cfa716d" dependencies = [ "bincode", - "borsh 1.5.3", + "borsh 1.5.4", "getrandom 0.2.15", "js-sys", "num-traits", @@ -2608,29 +2672,30 @@ dependencies = [ [[package]] name = "solana-last-restart-slot" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3186feae497bdfd2e77bfa56caed38b1cb1b0f389506666e3331f0b9ae799cb" +checksum = "fee98cc25000ee8bab1a4f63c7516d9521bc8a9747d8287ebb05e5d9b1d32ee1" dependencies = [ "serde", "serde_derive", "solana-sdk-macro", + "solana-sysvar-id", ] [[package]] name = "solana-log-collector" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b529f5736a6c0794a885dac2e091138d3db6d924335906f117a62b58b0d3b5dc" +checksum = "ff50f7d13f8e5ef4949066d5993a2f4a776a5d713dcd23c3af21c08383f6d3d5" dependencies = [ "log", ] [[package]] name = "solana-logger" -version = "2.1.6" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037e89416c5f3e160841a3717241f86e5a3e1b3edf4d946e976b4960c11e1073" +checksum = "05de5bd31b0123b9c2c8fa106ae11ad6cff45d77be67a9ac5109407322c58cd4" dependencies = [ "env_logger", "lazy_static", @@ -2639,15 +2704,15 @@ dependencies = [ [[package]] name = "solana-measure" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b2047a2f588082b71080b060918f107c3330ae1505f759c3b2d74bae9d9c88" +checksum = "a7ae355064c63c12ffadedc1c44d9410e0fd4f50923f0503a4367c1f64153d2c" [[package]] name = "solana-metrics" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6319c74238e8ed4f7159fd37c693a574ab8316d03b053103f9cc83dce13f1d5c" +checksum = "18f4af2c5fdda62f1cc6a88a124f5387aa85cb046dd37a992afa85ae05d59d7d" dependencies = [ "crossbeam-channel", "gethostname", @@ -2660,27 +2725,27 @@ dependencies = [ [[package]] name = "solana-msg" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7551f85064bc7299d56dbd7126258b084a2d78d0325b1579324f818b405123" +checksum = "fac7a109b0c7a0ed26c1fbf3b0fec8809b5d4c74b5d597f0252d45255fd0d309" dependencies = [ "solana-define-syscall", ] [[package]] name = "solana-native-token" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0c4074f5fc67574dabd8f30fe6e51e290a812d88326b19b49c462058e23340" +checksum = "7246817ae265f5a67be25f32ee52267f1c2fe29767ab601ef03c5086bfc64992" [[package]] name = "solana-packet" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dafc2d84e57dbfe32583fe915962bd2ca3af6be496628a871db3c3d697b38d7" +checksum = "4153becc47f7367102710ae3ddbae46b5aa1b004da4cab8101eaf7d6d0b911b0" dependencies = [ "bincode", - "bitflags 2.6.0", + "bitflags 2.8.0", "cfg_eval", "serde", "serde_derive", @@ -2689,9 +2754,9 @@ dependencies = [ [[package]] name = "solana-poseidon" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f193a65f0db7fe5615c76c2814d6450a2e4cda61f786d5bf7a6b1ad0c179b947" +checksum = "88a97dd90dd8cc62edf994c146b352fc430a87d7735bb672d6ed1a14d851cc96" dependencies = [ "ark-bn254", "light-poseidon", @@ -2701,9 +2766,9 @@ dependencies = [ [[package]] name = "solana-precompile-error" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a30ab58b9e37cde4e5577282670f30df71b97b6b06dbdb420e9b84e57b831227" +checksum = "9ed911c6c1ec277b55cf5f082a893023a8a7a58b520823d9ef65f36ace939f2b" dependencies = [ "num-traits", "solana-decode-error", @@ -2711,16 +2776,16 @@ dependencies = [ [[package]] name = "solana-program" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9040decf2f295d35da22557eeab3768ab8dfca8aed9afe668663c8fa0e97d60e" +checksum = "fb05f5ffadb039285ee82efd9a593e0873220f840f0eac7069d962f9eb29a407" dependencies = [ "base64 0.22.1", "bincode", - "bitflags 2.6.0", + "bitflags 2.8.0", "blake3", "borsh 0.10.4", - "borsh 1.5.3", + "borsh 1.5.4", "bs58", "bv", "bytemuck", @@ -2776,6 +2841,7 @@ dependencies = [ "solana-slot-hashes", "solana-slot-history", "solana-stable-layout", + "solana-sysvar-id", "solana-transaction-error", "thiserror 1.0.69", "wasm-bindgen", @@ -2783,9 +2849,9 @@ dependencies = [ [[package]] name = "solana-program-entrypoint" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb90f3fa3e979b912451a404508f1f90bb6e5c1d7767625f622b20016fb9fde" +checksum = "c5f6148e740c6deed55fe343355f0cb3ec158d221e11aa8bb93a392fa62c4137" dependencies = [ "solana-account-info", "solana-msg", @@ -2795,11 +2861,11 @@ dependencies = [ [[package]] name = "solana-program-error" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd089caeef26dd07bd12b7b67d45e92faddc2fc67a960f316df7ae4776a2f3d5" +checksum = "d87e99e4299728f450194b6adf946dde512d79d82275b1c73f6faea7e9075cef" dependencies = [ - "borsh 1.5.3", + "borsh 1.5.4", "num-traits", "serde", "serde_derive", @@ -2811,9 +2877,9 @@ dependencies = [ [[package]] name = "solana-program-memory" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed4bc044dc2b49c323aeff04aec03c908a052e278c2edf2f7616f32fc0f1bcd9" +checksum = "3691cdd84c0a4753b484f468aac19e0943fab1e71705b21d00d561ac6eea6449" dependencies = [ "num-traits", "solana-define-syscall", @@ -2821,24 +2887,24 @@ dependencies = [ [[package]] name = "solana-program-option" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3babbdffd81994c043fc9a61458ce87496218825d6e9a303de643c0a53089b9a" +checksum = "e99a3e016363a95cdbe23aaa2a68578ffa2ce8e37c4a642962201af6376ffc37" [[package]] name = "solana-program-pack" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fb28439d23e1f505e59c7a14ed5012365ab7aa0f20dc7bda048e02ff231cf6" +checksum = "4eba980dec9d5403ea299a3cdf27cd794e6b1a188acc8c5e3ae7d067b629eb24" dependencies = [ "solana-program-error", ] [[package]] name = "solana-program-runtime" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1de51df173401d50c0f4cf750f5070d7a4c82125a03c1aec9622dc041b0b54" +checksum = "554db6e468732aa8b0a06a6d4f7b9aa87c9af3e230cec0de3d114d05ae562516" dependencies = [ "base64 0.22.1", "bincode", @@ -2866,12 +2932,12 @@ dependencies = [ [[package]] name = "solana-pubkey" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea3215775fcedf200d47590c7e2ce9a3a46bc2b7d3f77d0eae9c6edf0a39aec" +checksum = "6dba2b19db8b73ab96b309b6d2a9f26386e45e2af3618a27b92389da9a3df1f1" dependencies = [ "borsh 0.10.4", - "borsh 1.5.3", + "borsh 1.5.4", "bs58", "bytemuck", "bytemuck_derive", @@ -2893,30 +2959,31 @@ dependencies = [ [[package]] name = "solana-rent" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab3f4a270196c38d62c3bb3c7a2f07732af2c772b50da49c9b1e2c9d2ace286" +checksum = "138b60a6683d14d63b4cee532d50afcb54999679b5c53013969fd51977455e14" dependencies = [ "serde", "serde_derive", "solana-sdk-macro", + "solana-sysvar-id", ] [[package]] name = "solana-sanitize" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203b90994371db8cade8e885f74ec9f68ee02a32b25d514594158b2551a4e5ed" +checksum = "58f71b885b953e9157b66eaba9a34507f2f840712ef54f483725ba510ee1bd89" [[package]] name = "solana-sdk" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524604d94185c189616296e5b7da1014cc96d1e446bd2b26f247f00708b9225a" +checksum = "74a9bcaaedaf805d5541307e22b48ba80a5b0e2922c2d35ca7f23732efa6bd07" dependencies = [ "bincode", - "bitflags 2.6.0", - "borsh 1.5.3", + "bitflags 2.8.0", + "borsh 1.5.4", "bs58", "bytemuck", "bytemuck_derive", @@ -2963,6 +3030,7 @@ dependencies = [ "solana-sanitize", "solana-sdk-macro", "solana-secp256k1-recover", + "solana-secp256r1-program", "solana-serde-varint", "solana-short-vec", "solana-signature", @@ -2973,42 +3041,56 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd2265b93dce9d3dcf9f395abf1a85b5e06e4da4aa60ca147620003ac3abc67" +checksum = "62f0b358f336ceac3827881915e5293f121c023cbd2150115046356c66898cb8" dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] name = "solana-secp256k1-recover" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2eef5a00a75648273c3fb6e3d85b0c8c02fcc1e36c4271664dcc39b6b128d41" +checksum = "460c2e36586bcce843cdeaaf2364f3db7fbd9f266325e93d5e9af33f2605dd7d" dependencies = [ - "borsh 1.5.3", + "borsh 1.5.4", "libsecp256k1", "solana-define-syscall", "thiserror 1.0.69", ] +[[package]] +name = "solana-secp256r1-program" +version = "2.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993ec6151c8f8ce77378a2506831c869b27ebdb0eaf65b375d38a4798c20d56" +dependencies = [ + "bytemuck", + "openssl", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-pubkey", +] + [[package]] name = "solana-serde-varint" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aeb51d3c20e2a61db0ef72617f3b8c9207a342a867af454a95f17add9f6c262" +checksum = "a98449030e53dcc2c4f160acab99b2bdb3e24ea8bff8ca6e71a6e539a54bf3d7" dependencies = [ "serde", ] [[package]] name = "solana-serialize-utils" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cfb0b57c6a431fb15ff33053caadb6c36aed4e1ce74bea9adfc459a710b3626" +checksum = "d659aac218580fc3fb3e8350669db9bb01bc1bc849c90f0741cbfccb6663eb94" dependencies = [ "solana-instruction", "solana-pubkey", @@ -3017,9 +3099,9 @@ dependencies = [ [[package]] name = "solana-sha256-hasher" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd115f3a1136314b0183235080d29023530c3a0a5df60505fdb7ea620eff9fd6" +checksum = "0db90ad6643d4d626f923159eaa876000c09f8c2e9aa7ff59b803e8328712582" dependencies = [ "sha2 0.10.8", "solana-define-syscall", @@ -3028,18 +3110,18 @@ dependencies = [ [[package]] name = "solana-short-vec" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08e55330b694db1139dcdf2a1ea7781abe8bd994dec2ab29e36abfd06e4e9274" +checksum = "11f7de721a6c50cb3a41e027a623496be39e45c452fbf897f657cd1f2f67dbbd" dependencies = [ "serde", ] [[package]] name = "solana-signature" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad9784d110f195a3a4fe423479d18f05b01a1c380a1430644a3b3038fdbe2f0" +checksum = "3123b0fba3a798cbb2091788c92880644464e56359abc7defed993c6efa88ef3" dependencies = [ "bs58", "ed25519-dalek", @@ -3052,31 +3134,33 @@ dependencies = [ [[package]] name = "solana-slot-hashes" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17d216c0ebf00e95acaf2b1e227e6cc900a5ce50fb81fa0743272851e88a788d" +checksum = "3840867aa6d0fac65d3a4c1f14fff650a8e148732a16c06ebd8a2389d79d4745" dependencies = [ "serde", "serde_derive", "solana-hash", + "solana-sysvar-id", ] [[package]] name = "solana-slot-history" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88cbcdf767891c6a40116a5ef8f7241000f074ece4ba80c8f00b4f62705fc8a4" +checksum = "101583a12fcce9b52f845b3c773f4ae6c3f4ca6a46177dadbd83e276baf82326" dependencies = [ "bv", "serde", "serde_derive", + "solana-sysvar-id", ] [[package]] name = "solana-stable-layout" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a5305ca88fb5deb219cd88f04e24f3a131769417d7fcb11a8da1126a8f98d23" +checksum = "9e1b923e1c9e42b6c98b1786ca003af6a0366932f08d63432e984fcc394b7b5e" dependencies = [ "solana-instruction", "solana-pubkey", @@ -3084,9 +3168,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "242634cdc1eacaa83738cc100fdd583eb88f99cc2edcc900c8ebe57d77af51b1" +checksum = "7f37c7ac5c53f2a0c5222f24146ad8bf7ce84e96551997c05984264d5bdae1a9" dependencies = [ "bincode", "log", @@ -3098,11 +3182,20 @@ dependencies = [ "solana-type-overrides", ] +[[package]] +name = "solana-sysvar-id" +version = "2.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59351de877a7cf0cea0e436424ecf4ea0c08c59ff01ef0575436972b920b818c" +dependencies = [ + "solana-pubkey", +] + [[package]] name = "solana-timings" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a8e2f926d488c1e2a65cbc05544dcb68cfa88deb4d50f89db5bfbda7ff2419" +checksum = "743bca35719b09d4d9abac84fce42a448d86eb62edc69404ce85077874469e46" dependencies = [ "eager", "enum-iterator", @@ -3111,9 +3204,9 @@ dependencies = [ [[package]] name = "solana-transaction-error" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a4bea6d80b34fe6e785d19bf928fe103928d1f6c9935ec23bb6a9d4d7a33d2" +checksum = "1c3d2147cfaad2a5518b8e15621008699e28d32d6233cd7a6b27a506e01f1515" dependencies = [ "serde", "serde_derive", @@ -3123,9 +3216,9 @@ dependencies = [ [[package]] name = "solana-type-overrides" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2066f25d460d63801f91436c2640aaba4f2dc95aa18fe1e76f7f2c063e981d4e" +checksum = "b3cac7e7628c46bf5e243a4b0f11c0ad172a27cae2a5d97c7c6ca64fe9e6ece6" dependencies = [ "lazy_static", "rand 0.8.5", @@ -3133,9 +3226,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "2.1.0" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab46788981765ee706094ca53ad8421aae0286a6b948e892fa7db88992a5373" +checksum = "490e9e84d72423b90f1adcc232051a4e3719bf3498508ea9ba9d15e967f4d327" dependencies = [ "itertools 0.12.1", "log", @@ -3184,7 +3277,7 @@ dependencies = [ "serial_test", "solana-program", "solana-sdk", - "thiserror 2.0.8", + "thiserror 2.0.11", ] [[package]] @@ -3218,9 +3311,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -3241,7 +3334,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -3267,12 +3360,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.2.15", "once_cell", "rustix", "windows-sys 0.59.0", @@ -3298,11 +3392,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.8" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl 2.0.8", + "thiserror-impl 2.0.11", ] [[package]] @@ -3313,18 +3407,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] name = "thiserror-impl" -version = "2.0.8" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -3339,9 +3433,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -3354,9 +3448,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.42.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -3513,6 +3607,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -3557,34 +3657,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", @@ -3595,9 +3696,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3605,28 +3706,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -3819,9 +3923,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" dependencies = [ "memchr", ] @@ -3868,7 +3972,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", "synstructure", ] @@ -3890,7 +3994,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -3910,7 +4014,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", "synstructure", ] @@ -3931,7 +4035,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] [[package]] @@ -3953,5 +4057,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.96", ] diff --git a/program/Cargo.toml b/program/Cargo.toml index 21b18ad..66123c2 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -22,7 +22,7 @@ thiserror = "2.0" [dev-dependencies] lazy_static = "1.5.0" -mollusk-svm = "0.0.13" +mollusk-svm = { version = "0.0.13", git = "https://github.com/buffalojoec/mollusk.git" } proptest = "1.5" serial_test = "3.2.0" solana-sdk = "2.1.0" diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs index ab5de7c..0143a11 100644 --- a/program/tests/assert_instruction_count.rs +++ b/program/tests/assert_instruction_count.rs @@ -5,7 +5,7 @@ mod setup; use { mollusk_svm::{result::Check, Mollusk}, solana_sdk::{ - account::{AccountSharedData, ReadableAccount}, + account::{Account as SolanaAccount, ReadableAccount}, program_pack::Pack, pubkey::Pubkey, }, @@ -29,7 +29,7 @@ fn initialize_mint() { let mint_account = { let space = Mint::LEN; let lamports = mollusk.sysvars.rent.minimum_balance(space); - AccountSharedData::new(lamports, space, &id()) + SolanaAccount::new(lamports, space, &id()) }; mollusk.process_and_validate_instruction( @@ -61,7 +61,7 @@ fn initialize_account() { let token_account = { let space = Account::LEN; let lamports = mollusk.sysvars.rent.minimum_balance(space); - AccountSharedData::new(lamports, space, &id()) + SolanaAccount::new(lamports, space, &id()) }; mollusk.process_and_validate_instruction( @@ -69,7 +69,7 @@ fn initialize_account() { &[ (account, token_account), (mint, mint_account), - (owner, AccountSharedData::default()), + (owner, SolanaAccount::default()), mollusk.sysvars.keyed_account_for_rent_sysvar(), ], &[ @@ -99,7 +99,7 @@ fn mint_to() { &[ (mint, mint_account), (account, token_account), - (owner, AccountSharedData::default()), + (owner, SolanaAccount::default()), ], &[ Check::success(), @@ -133,7 +133,7 @@ fn transfer() { &[ (source, source_token_account), (destination, destination_token_account), - (owner, AccountSharedData::default()), + (owner, SolanaAccount::default()), ], &[ Check::success(), @@ -165,7 +165,7 @@ fn burn() { &[ (mint, mint_account), (account, token_account), - (owner, AccountSharedData::default()), + (owner, SolanaAccount::default()), ], &[ Check::success(), @@ -194,7 +194,7 @@ fn close_account() { &[ (mint, mint_account), (account, token_account), - (owner, AccountSharedData::default()), + (owner, SolanaAccount::default()), ], &[Check::success(), Check::account(&account).closed().build()], ); diff --git a/program/tests/close_account.rs b/program/tests/close_account.rs index 7cfbb06..cb1ac55 100644 --- a/program/tests/close_account.rs +++ b/program/tests/close_account.rs @@ -5,7 +5,7 @@ mod setup; use { mollusk_svm::{result::Check, Mollusk}, solana_sdk::{ - account::{AccountSharedData, ReadableAccount}, + account::{Account as SolanaAccount, ReadableAccount}, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, @@ -24,7 +24,7 @@ fn success_init_after_close_account() { let destination = Pubkey::new_unique(); let decimals = 9; - let owner_account = AccountSharedData::new(1_000_000_000, 0, &system_program::id()); + let owner_account = SolanaAccount::new(1_000_000_000, 0, &system_program::id()); let mint_account = setup::setup_mint_account(None, None, 0, decimals); let token_account = setup::setup_token_account(&mint, &owner, 0); @@ -32,36 +32,45 @@ fn success_init_after_close_account() { mollusk.process_and_validate_instruction_chain( &[ - instruction::close_account(&spl_token::id(), &account, &destination, &owner, &[]) - .unwrap(), - system_instruction::create_account( - &owner, - &account, - 1_000_000_000, - Account::LEN as u64, - &spl_token::id(), + ( + &instruction::close_account(&spl_token::id(), &account, &destination, &owner, &[]) + .unwrap(), + &[Check::success()], + ), + ( + &system_instruction::create_account( + &owner, + &account, + 1_000_000_000, + Account::LEN as u64, + &spl_token::id(), + ), + &[Check::success()], + ), + ( + &instruction::initialize_account(&spl_token::id(), &account, &mint, &owner) + .unwrap(), + &[ + Check::success(), + // Account successfully re-initialized. + Check::account(&account) + .data(setup::setup_token_account(&mint, &owner, 0).data()) + .owner(&spl_token::id()) + .build(), + // The destination should have the lamports from the closed account. + Check::account(&destination) + .lamports(expected_destination_lamports) + .build(), + ], ), - instruction::initialize_account(&spl_token::id(), &account, &mint, &owner).unwrap(), ], &[ (mint, mint_account), (account, token_account), (owner, owner_account), - (destination, AccountSharedData::default()), + (destination, SolanaAccount::default()), mollusk.sysvars.keyed_account_for_rent_sysvar(), ], - &[ - Check::success(), - // Account successfully re-initialized. - Check::account(&account) - .data(setup::setup_token_account(&mint, &owner, 0).data()) - .owner(&spl_token::id()) - .build(), - // The destination should have the lamports from the closed account. - Check::account(&destination) - .lamports(expected_destination_lamports) - .build(), - ], ); } @@ -75,7 +84,7 @@ fn fail_init_after_close_account() { let destination = Pubkey::new_unique(); let decimals = 9; - let owner_account = AccountSharedData::new(1_000_000_000, 0, &system_program::id()); + let owner_account = SolanaAccount::new(1_000_000_000, 0, &system_program::id()); let mint_account = setup::setup_mint_account(None, None, 0, decimals); let token_account = setup::setup_token_account(&mint, &owner, 0); @@ -83,29 +92,38 @@ fn fail_init_after_close_account() { mollusk.process_and_validate_instruction_chain( &[ - instruction::close_account(&spl_token::id(), &account, &destination, &owner, &[]) - .unwrap(), - system_instruction::transfer(&owner, &account, 1_000_000_000), - instruction::initialize_account(&spl_token::id(), &account, &mint, &owner).unwrap(), + ( + &instruction::close_account(&spl_token::id(), &account, &destination, &owner, &[]) + .unwrap(), + &[Check::success()], + ), + ( + &system_instruction::transfer(&owner, &account, 1_000_000_000), + &[Check::success()], + ), + ( + &instruction::initialize_account(&spl_token::id(), &account, &mint, &owner) + .unwrap(), + &[ + Check::err(ProgramError::InvalidAccountData), + // Account not re-initialized. + Check::account(&account) + .lamports(1_000_000_000) + .owner(&system_program::id()) + .build(), + // The destination should have the lamports from the closed account. + Check::account(&destination) + .lamports(expected_destination_lamports) + .build(), + ], + ), ], &[ (mint, mint_account), (account, token_account), (owner, owner_account), - (destination, AccountSharedData::default()), + (destination, SolanaAccount::default()), mollusk.sysvars.keyed_account_for_rent_sysvar(), ], - &[ - Check::err(ProgramError::InvalidAccountData), - // Account not re-initialized. - Check::account(&account) - .lamports(1_000_000_000) - .owner(&system_program::id()) - .build(), - // The destination should have the lamports from the closed account. - Check::account(&destination) - .lamports(expected_destination_lamports) - .build(), - ], ); } diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 32e0779..1fd1edc 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -3,12 +3,10 @@ //! Program state processor tests use { - mollusk_svm::Mollusk, + mollusk_svm::{result::Check, Mollusk}, serial_test::serial, solana_sdk::{ - account::{ - create_account_for_test, Account as SolanaAccount, AccountSharedData, ReadableAccount, - }, + account::{create_account_for_test, Account as SolanaAccount, ReadableAccount}, account_info::{AccountInfo, IntoAccountInfo}, entrypoint::ProgramResult, instruction::Instruction, @@ -31,35 +29,25 @@ use { }, state::{Account, AccountState, Mint, Multisig}, }, - std::{ - collections::HashMap, - sync::{Arc, RwLock}, - }, + std::collections::HashMap, }; -lazy_static::lazy_static! { - static ref EXPECTED_DATA: Arc>> = Arc::new(RwLock::new(Vec::new())); -} - fn do_process_instruction( instruction: Instruction, mut accounts: Vec<&mut SolanaAccount>, + checks: &[Check], ) -> ProgramResult { // Prepare accounts for mollusk. - let instruction_accounts: Vec<(Pubkey, AccountSharedData)> = instruction + let instruction_accounts: Vec<(Pubkey, SolanaAccount)> = instruction .accounts .iter() .zip(&accounts) - .map(|(account_meta, account)| { - ( - account_meta.pubkey, - AccountSharedData::from((*account).clone()), - ) - }) + .map(|(account_meta, account)| (account_meta.pubkey, (*account).clone())) .collect(); let mollusk = Mollusk::new(&spl_token::ID, "spl_token"); - let result = mollusk.process_instruction(&instruction, &instruction_accounts); + let result = + mollusk.process_and_validate_instruction(&instruction, &instruction_accounts, checks); // Update accounts after the instruction is processed. for (original, (_, updated)) in accounts @@ -79,6 +67,7 @@ fn do_process_instruction( fn do_process_instruction_dups( instruction: Instruction, account_infos: Vec, + checks: &[Check], ) -> ProgramResult { let mut cached_accounts = HashMap::new(); let mut dedup_accounts = Vec::new(); @@ -93,21 +82,22 @@ fn do_process_instruction_dups( executable: account_info.executable, rent_epoch: account_info.rent_epoch, }; - dedup_accounts.push((*account_info.key, AccountSharedData::from(account))); + dedup_accounts.push((*account_info.key, account)); cached_accounts.insert(account_info.key, account_info); } }); let mollusk = Mollusk::new(&spl_token::ID, "spl_token"); - let result = mollusk.process_instruction(&instruction, &dedup_accounts); + let result = mollusk.process_and_validate_instruction(&instruction, &dedup_accounts, checks); // Update accounts after the instruction is processed. result .resulting_accounts .into_iter() .for_each(|(pubkey, account)| { + let account = account.clone(); let account_info = cached_accounts.get(&pubkey).unwrap(); - if account.data().is_empty() { + if account.data.is_empty() { // When the account is closed, the tests expect the data to // be zeroed. account_info.try_borrow_mut_data().unwrap().fill(0); @@ -126,10 +116,6 @@ fn do_process_instruction_dups( .map_err(|e| ProgramError::try_from(e).unwrap()) } -fn set_expected_data(expected_data: Vec) { - *EXPECTED_DATA.write().unwrap() = expected_data; -} - fn rent_sysvar() -> SolanaAccount { create_account_for_test(&Rent::default()) } @@ -162,7 +148,8 @@ fn test_initialize_mint() { Err(TokenError::NotRentExempt.into()), do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account, &mut rent_sysvar] + vec![&mut mint_account, &mut rent_sysvar], + &[Check::err(TokenError::NotRentExempt.into())], ) ); @@ -172,6 +159,7 @@ fn test_initialize_mint() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -180,7 +168,8 @@ fn test_initialize_mint() { Err(TokenError::AlreadyInUse.into()), do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account, &mut rent_sysvar] + vec![&mut mint_account, &mut rent_sysvar], + &[Check::err(TokenError::AlreadyInUse.into())], ) ); @@ -188,6 +177,17 @@ fn test_initialize_mint() { do_process_instruction( initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), vec![&mut mint2_account, &mut rent_sysvar], + &[ + Check::success(), + // freeze authority is set + Check::account(&mint2_key) + .data_slice(46, &[1, 0, 0, 0]) + .build(), + // freeze authority matches owner + Check::account(&mint2_key) + .data_slice(50, owner_key.as_ref()) + .build(), + ], ) .unwrap(); let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); @@ -209,7 +209,8 @@ fn test_initialize_mint2() { Err(TokenError::NotRentExempt.into()), do_process_instruction( initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), - vec![&mut mint_account] + vec![&mut mint_account], + &[Check::err(TokenError::NotRentExempt.into())], ) ); @@ -219,6 +220,7 @@ fn test_initialize_mint2() { do_process_instruction( initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account], + &[Check::success()], ) .unwrap(); @@ -227,7 +229,8 @@ fn test_initialize_mint2() { Err(TokenError::AlreadyInUse.into()), do_process_instruction( initialize_mint2(&program_id, &mint_key, &owner_key, None, 2,).unwrap(), - vec![&mut mint_account] + vec![&mut mint_account], + &[Check::err(TokenError::AlreadyInUse.into())], ) ); @@ -235,6 +238,17 @@ fn test_initialize_mint2() { do_process_instruction( initialize_mint2(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), vec![&mut mint2_account], + &[ + Check::success(), + // freeze authority is set + Check::account(&mint2_key) + .data_slice(46, &[1, 0, 0, 0]) + .build(), + // freeze authority matches owner + Check::account(&mint2_key) + .data_slice(50, owner_key.as_ref()) + .build(), + ], ) .unwrap(); let mint = Mint::unpack_unchecked(&mint2_account.data).unwrap(); @@ -264,6 +278,7 @@ fn test_initialize_mint_account() { &mut owner_account, &mut rent_sysvar ], + &[Check::err(TokenError::NotRentExempt.into())], ) ); @@ -280,6 +295,7 @@ fn test_initialize_mint_account() { &mut owner_account, &mut rent_sysvar ], + &[Check::err(TokenError::InvalidMint.into())], ) ); @@ -287,6 +303,7 @@ fn test_initialize_mint_account() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -303,6 +320,7 @@ fn test_initialize_mint_account() { &mut owner_account, &mut rent_sysvar ], + &[Check::err(ProgramError::IncorrectProgramId)], ) ); mint_account.owner = program_id; @@ -316,6 +334,7 @@ fn test_initialize_mint_account() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -330,6 +349,7 @@ fn test_initialize_mint_account() { &mut owner_account, &mut rent_sysvar ], + &[Check::err(TokenError::AlreadyInUse.into())], ) ); } @@ -387,6 +407,7 @@ fn test_transfer_dups() { do_process_instruction_dups( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![mint_info.clone(), rent_info.clone()], + &[Check::success()], ) .unwrap(); @@ -399,6 +420,7 @@ fn test_transfer_dups() { account1_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -411,6 +433,7 @@ fn test_transfer_dups() { owner_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -418,6 +441,7 @@ fn test_transfer_dups() { do_process_instruction_dups( mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); @@ -437,6 +461,7 @@ fn test_transfer_dups() { account2_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -459,6 +484,7 @@ fn test_transfer_dups() { account2_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -485,6 +511,7 @@ fn test_transfer_dups() { account2_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -507,6 +534,7 @@ fn test_transfer_dups() { account2_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -519,11 +547,13 @@ fn test_transfer_dups() { account2_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); do_process_instruction_dups( mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); @@ -544,6 +574,7 @@ fn test_transfer_dups() { account2_info.clone(), account2_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -566,6 +597,7 @@ fn test_transfer_dups() { account2_info.clone(), account2_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -577,6 +609,7 @@ fn test_transfer_dups() { rent_info.clone(), account4_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -588,12 +621,14 @@ fn test_transfer_dups() { multisig_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); do_process_instruction_dups( mint_to(&program_id, &mint_key, &account4_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account4_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); @@ -614,6 +649,7 @@ fn test_transfer_dups() { multisig_info.clone(), account4_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -637,6 +673,7 @@ fn test_transfer_dups() { multisig_info.clone(), account4_info.clone(), ], + &[Check::success()], ) .unwrap(); } @@ -684,6 +721,7 @@ fn test_transfer() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -696,6 +734,7 @@ fn test_transfer() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -708,6 +747,7 @@ fn test_transfer() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -720,6 +760,7 @@ fn test_transfer() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -732,6 +773,7 @@ fn test_transfer() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); @@ -742,6 +784,7 @@ fn test_transfer() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -765,6 +808,7 @@ fn test_transfer() { &mut account2_account, &mut owner_account, ], + &[Check::err(ProgramError::MissingRequiredSignature)], ) ); @@ -786,6 +830,7 @@ fn test_transfer() { &mut mismatch_account, &mut owner_account, ], + &[Check::err(TokenError::MintMismatch.into())], ) ); @@ -807,6 +852,7 @@ fn test_transfer() { &mut account2_account, &mut owner2_account, ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -822,6 +868,7 @@ fn test_transfer() { &mut account2_account, &mut owner2_account, ], + &[Check::err(ProgramError::IncorrectProgramId)], ) ); account_account.owner = program_id; @@ -838,6 +885,7 @@ fn test_transfer() { &mut account2_account, &mut owner2_account, ], + &[Check::err(ProgramError::IncorrectProgramId)], ) ); account2_account.owner = program_id; @@ -858,6 +906,7 @@ fn test_transfer() { &mut account2_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -871,6 +920,7 @@ fn test_transfer() { &mut account2_account, &mut owner_account, ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -890,6 +940,7 @@ fn test_transfer() { &mut account_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -914,6 +965,7 @@ fn test_transfer() { &mut account_account, &mut owner_account, ], + &[Check::err(TokenError::MintDecimalsMismatch.into())], ) ); @@ -938,6 +990,7 @@ fn test_transfer() { &mut account_account, &mut owner_account, ], + &[Check::err(TokenError::MintMismatch.into())], ) ); // transfer rest with explicit decimals @@ -959,6 +1012,7 @@ fn test_transfer() { &mut account_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -972,6 +1026,7 @@ fn test_transfer() { &mut account_account, &mut owner_account, ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -991,6 +1046,7 @@ fn test_transfer() { &mut delegate_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -1012,6 +1068,7 @@ fn test_transfer() { &mut account2_account, &mut owner2_account, ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -1033,6 +1090,7 @@ fn test_transfer() { &mut account2_account, &mut delegate_account, ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -1052,6 +1110,7 @@ fn test_transfer() { &mut account2_account, &mut delegate_account, ], + &[Check::success()], ) .unwrap(); @@ -1073,6 +1132,7 @@ fn test_transfer() { &mut account2_account, &mut delegate_account, ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -1092,6 +1152,7 @@ fn test_transfer() { &mut account2_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -1111,6 +1172,7 @@ fn test_transfer() { &mut delegate_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -1132,6 +1194,7 @@ fn test_transfer() { &mut account2_account, &mut delegate_account, ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); } @@ -1172,6 +1235,7 @@ fn test_self_transfer() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -1184,6 +1248,7 @@ fn test_self_transfer() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -1196,6 +1261,7 @@ fn test_self_transfer() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -1208,6 +1274,7 @@ fn test_self_transfer() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -1215,6 +1282,7 @@ fn test_self_transfer() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -1244,6 +1312,12 @@ fn test_self_transfer() { account_info.clone(), owner_info.clone(), ], + &[ + Check::success(), + Check::account(account_info.key) + .data_slice(64, &1000u64.to_le_bytes()) + .build() + ], ) ); // no balance change... @@ -1272,6 +1346,12 @@ fn test_self_transfer() { account_info.clone(), owner_info.clone(), ], + &[ + Check::success(), + Check::account(account_info.key) + .data_slice(64, &1000u64.to_le_bytes()) + .build() + ], ) ); // no balance change... @@ -1300,6 +1380,7 @@ fn test_self_transfer() { account_info.clone(), owner_no_sign_info.clone(), ], + &[Check::err(ProgramError::MissingRequiredSignature)], ) ); @@ -1326,6 +1407,7 @@ fn test_self_transfer() { account_info.clone(), owner_no_sign_info, ], + &[Check::err(ProgramError::MissingRequiredSignature)], ) ); @@ -1348,6 +1430,7 @@ fn test_self_transfer() { account_info.clone(), owner2_info.clone(), ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -1373,6 +1456,7 @@ fn test_self_transfer() { account_info.clone(), owner2_info.clone(), ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -1395,6 +1479,7 @@ fn test_self_transfer() { account_info.clone(), owner_info.clone(), ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -1420,6 +1505,7 @@ fn test_self_transfer() { account_info.clone(), owner_info.clone(), ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -1445,6 +1531,7 @@ fn test_self_transfer() { account_info.clone(), owner_info.clone(), ], + &[Check::err(TokenError::MintDecimalsMismatch.into())], ) ); @@ -1470,6 +1557,7 @@ fn test_self_transfer() { account_info.clone(), owner_info.clone(), ], + &[Check::err(TokenError::MintMismatch.into())], ) ); @@ -1490,6 +1578,7 @@ fn test_self_transfer() { delegate_info.clone(), owner_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -1512,6 +1601,15 @@ fn test_self_transfer() { account_info.clone(), delegate_info.clone(), ], + &[ + Check::success(), + Check::account(account_info.key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + Check::account(&account_key) + .data_slice(121, &100u64.to_le_bytes()) + .build(), + ], ) ); // no balance change... @@ -1541,6 +1639,15 @@ fn test_self_transfer() { account_info.clone(), delegate_info.clone(), ], + &[ + Check::success(), + Check::account(account_info.key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + Check::account(&account_key) + .data_slice(121, &100u64.to_le_bytes()) + .build(), + ], ) ); // no balance change... @@ -1567,6 +1674,7 @@ fn test_self_transfer() { account_info.clone(), delegate_info.clone(), ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -1592,6 +1700,7 @@ fn test_self_transfer() { account_info.clone(), delegate_info.clone(), ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -1614,6 +1723,12 @@ fn test_self_transfer() { account_info.clone(), owner_info.clone(), ], + &[ + Check::success(), + Check::account(account_info.key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + ], ) ); // no balance change... @@ -1642,6 +1757,12 @@ fn test_self_transfer() { account_info.clone(), owner_info.clone(), ], + &[ + Check::success(), + Check::account(account_info.key) + .data_slice(64, &1000u64.to_le_bytes()) + .build(), + ], ) ); // no balance change... @@ -1667,22 +1788,26 @@ fn test_mintable_token_with_zero_supply() { // create mint-able token with zero supply let decimals = 2; + let expected_mint = Mint { + mint_authority: COption::Some(owner_key), + supply: 0, + decimals, + is_initialized: true, + freeze_authority: COption::None, + }; + let mut mint_data = [0u8; Mint::LEN]; + expected_mint.pack_into_slice(&mut mint_data); do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, decimals).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[ + Check::success(), + Check::account(&mint_key).data(&mint_data).build(), + ], ) .unwrap(); let mint = Mint::unpack_unchecked(&mint_account.data).unwrap(); - assert_eq!( - mint, - Mint { - mint_authority: COption::Some(owner_key), - supply: 0, - decimals, - is_initialized: true, - freeze_authority: COption::None, - } - ); + assert_eq!(mint, expected_mint); // create account do_process_instruction( @@ -1693,6 +1818,7 @@ fn test_mintable_token_with_zero_supply() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -1700,6 +1826,12 @@ fn test_mintable_token_with_zero_supply() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &42u64.to_le_bytes()) + .build(), + ], ) .unwrap(); let _ = Mint::unpack(&mint_account.data).unwrap(); @@ -1721,6 +1853,12 @@ fn test_mintable_token_with_zero_supply() { ) .unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[ + Check::err(TokenError::MintDecimalsMismatch.into()), + Check::account(&account_key) + .data_slice(64, &42u64.to_le_bytes()) + .build(), + ], ) ); @@ -1741,6 +1879,12 @@ fn test_mintable_token_with_zero_supply() { ) .unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &84u64.to_le_bytes()) + .build(), + ], ) .unwrap(); let _ = Mint::unpack(&mint_account.data).unwrap(); @@ -1794,6 +1938,7 @@ fn test_approve_dups() { do_process_instruction_dups( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![mint_info.clone(), rent_info.clone()], + &[Check::success()], ) .unwrap(); @@ -1806,6 +1951,7 @@ fn test_approve_dups() { account1_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -1818,6 +1964,7 @@ fn test_approve_dups() { owner_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -1825,6 +1972,7 @@ fn test_approve_dups() { do_process_instruction_dups( mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); @@ -1844,6 +1992,7 @@ fn test_approve_dups() { account2_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -1866,6 +2015,7 @@ fn test_approve_dups() { account2_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -1873,6 +2023,7 @@ fn test_approve_dups() { do_process_instruction_dups( revoke(&program_id, &account1_key, &account1_key, &[]).unwrap(), vec![account1_info.clone(), account1_info.clone()], + &[Check::success()], ) .unwrap(); @@ -1884,6 +2035,7 @@ fn test_approve_dups() { rent_info.clone(), account3_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -1895,12 +2047,14 @@ fn test_approve_dups() { multisig_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); do_process_instruction_dups( mint_to(&program_id, &mint_key, &account3_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account3_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); @@ -1921,6 +2075,7 @@ fn test_approve_dups() { multisig_info.clone(), account3_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -1944,6 +2099,7 @@ fn test_approve_dups() { multisig_info.clone(), account3_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -1955,6 +2111,7 @@ fn test_approve_dups() { multisig_info.clone(), account3_info.clone(), ], + &[Check::success()], ) .unwrap(); } @@ -1989,6 +2146,7 @@ fn test_approve() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -2001,6 +2159,7 @@ fn test_approve() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -2013,6 +2172,7 @@ fn test_approve() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -2020,6 +2180,7 @@ fn test_approve() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -2043,6 +2204,7 @@ fn test_approve() { &mut delegate_account, &mut owner_account, ], + &[Check::err(ProgramError::MissingRequiredSignature)], ) ); @@ -2064,6 +2226,7 @@ fn test_approve() { &mut delegate_account, &mut owner2_account, ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -2083,6 +2246,7 @@ fn test_approve() { &mut delegate_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -2107,6 +2271,7 @@ fn test_approve() { &mut delegate_account, &mut owner_account, ], + &[Check::err(TokenError::MintDecimalsMismatch.into())], ) ); @@ -2131,6 +2296,7 @@ fn test_approve() { &mut delegate_account, &mut owner_account, ], + &[Check::err(TokenError::MintMismatch.into())], ) ); @@ -2153,6 +2319,7 @@ fn test_approve() { &mut delegate_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -2160,6 +2327,7 @@ fn test_approve() { do_process_instruction( revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), vec![&mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); } @@ -2187,6 +2355,7 @@ fn test_set_authority_dups() { do_process_instruction_dups( initialize_mint(&program_id, &mint_key, &mint_key, Some(&mint_key), 2).unwrap(), vec![mint_info.clone(), rent_info.clone()], + &[Check::success()], ) .unwrap(); @@ -2199,6 +2368,7 @@ fn test_set_authority_dups() { account1_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -2214,6 +2384,7 @@ fn test_set_authority_dups() { ) .unwrap(), vec![mint_info.clone(), mint_info.clone()], + &[Check::success()], ) .unwrap(); @@ -2229,6 +2400,7 @@ fn test_set_authority_dups() { ) .unwrap(), vec![mint_info.clone(), mint_info.clone()], + &[Check::success()], ) .unwrap(); @@ -2244,6 +2416,7 @@ fn test_set_authority_dups() { ) .unwrap(), vec![account1_info.clone(), account1_info.clone()], + &[Check::success()], ) .unwrap(); @@ -2263,6 +2436,7 @@ fn test_set_authority_dups() { ) .unwrap(), vec![account1_info.clone(), account1_info.clone()], + &[Check::success()], ) .unwrap(); } @@ -2300,6 +2474,7 @@ fn test_set_authority() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -2307,6 +2482,7 @@ fn test_set_authority() { do_process_instruction( initialize_mint(&program_id, &mint2_key, &owner_key, Some(&owner_key), 2).unwrap(), vec![&mut mint2_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -2324,6 +2500,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut account_account, &mut owner_account], + &[Check::err(ProgramError::UninitializedAccount)], ) ); @@ -2336,6 +2513,7 @@ fn test_set_authority() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -2348,6 +2526,7 @@ fn test_set_authority() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -2365,6 +2544,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut account_account, &mut owner2_account], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -2381,7 +2561,11 @@ fn test_set_authority() { instruction.accounts[1].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut account_account, &mut owner_account,],) + do_process_instruction( + instruction, + vec![&mut account_account, &mut owner_account,], + &[Check::err(ProgramError::MissingRequiredSignature)] + ), ); // wrong authority type @@ -2398,6 +2582,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut account_account, &mut owner_account], + &[Check::err(TokenError::AuthorityTypeNotSupported.into())], ) ); @@ -2415,6 +2600,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut account_account, &mut owner_account], + &[Check::err(TokenError::InvalidInstruction.into())], ) ); @@ -2434,6 +2620,21 @@ fn test_set_authority() { &mut owner2_account, &mut owner_account, ], + &[ + Check::success(), + // delegate set + Check::account(&account_key) + .data_slice(72, &[1, 0, 0, 0]) + .build(), + // delegate + Check::account(&account_key) + .data_slice(76, owner2_key.as_ref()) + .build(), + // delegated amount + Check::account(&account_key) + .data_slice(121, &u64::MAX.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -2452,6 +2653,17 @@ fn test_set_authority() { ) .unwrap(), vec![&mut account_account, &mut owner_account], + &[ + Check::success(), + // delegate not set + Check::account(&account_key) + .data_slice(72, &[0, 0, 0, 0]) + .build(), + // delegated amount + Check::account(&account_key) + .data_slice(121, &0u64.to_le_bytes()) + .build(), + ], ) .unwrap(); @@ -2472,6 +2684,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut account_account, &mut owner3_account], + &[Check::success()], ) .unwrap(); @@ -2487,6 +2700,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut account_account, &mut owner2_account], + &[Check::success()], ) .unwrap(); @@ -2502,6 +2716,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut account_account, &mut owner2_account], + &[Check::success()], ) .unwrap(); @@ -2519,6 +2734,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut mint_account, &mut owner2_account], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -2535,7 +2751,11 @@ fn test_set_authority() { instruction.accounts[1].is_signer = false; assert_eq!( Err(ProgramError::MissingRequiredSignature), - do_process_instruction(instruction, vec![&mut mint_account, &mut owner_account],) + do_process_instruction( + instruction, + vec![&mut mint_account, &mut owner_account], + &[Check::err(ProgramError::MissingRequiredSignature)] + ), ); // cannot freeze @@ -2552,6 +2772,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut mint_account, &mut owner_account], + &[Check::err(TokenError::MintCannotFreeze.into())], ) ); @@ -2567,6 +2788,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut mint_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -2582,6 +2804,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut mint_account, &mut owner2_account], + &[Check::success()], ) .unwrap(); @@ -2599,6 +2822,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut mint_account, &mut owner_account], + &[Check::err(TokenError::FixedSupply.into())], ) ); @@ -2614,6 +2838,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut mint2_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -2629,6 +2854,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut mint2_account, &mut owner2_account], + &[Check::success()], ) .unwrap(); @@ -2645,6 +2871,7 @@ fn test_set_authority() { ) .unwrap(), vec![&mut mint2_account, &mut owner2_account], + &[Check::err(TokenError::MintCannotFreeze.into())], ) ); } @@ -2674,6 +2901,7 @@ fn test_mint_to_dups() { do_process_instruction_dups( initialize_mint(&program_id, &mint_key, &mint_key, None, 2).unwrap(), vec![mint_info.clone(), rent_info.clone()], + &[Check::success()], ) .unwrap(); @@ -2686,6 +2914,7 @@ fn test_mint_to_dups() { owner_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -2693,6 +2922,7 @@ fn test_mint_to_dups() { do_process_instruction_dups( mint_to(&program_id, &mint_key, &account1_key, &mint_key, &[], 42).unwrap(), vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + &[Check::success()], ) .unwrap(); @@ -2700,6 +2930,7 @@ fn test_mint_to_dups() { do_process_instruction_dups( mint_to_checked(&program_id, &mint_key, &account1_key, &mint_key, &[], 42, 2).unwrap(), vec![mint_info.clone(), account1_info.clone(), mint_info.clone()], + &[Check::success()], ) .unwrap(); @@ -2722,6 +2953,7 @@ fn test_mint_to_dups() { account1_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -2741,6 +2973,7 @@ fn test_mint_to_dups() { account1_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); } @@ -2792,6 +3025,7 @@ fn test_mint_to() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -2804,6 +3038,7 @@ fn test_mint_to() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -2816,6 +3051,7 @@ fn test_mint_to() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -2828,6 +3064,7 @@ fn test_mint_to() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -2840,6 +3077,7 @@ fn test_mint_to() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); @@ -2850,6 +3088,15 @@ fn test_mint_to() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 42).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[ + Check::success(), + Check::account(&mint_key) + .data_slice(36, &42u64.to_le_bytes()) + .build(), + Check::account(&account_key) + .data_slice(64, &42u64.to_le_bytes()) + .build(), + ], ) .unwrap(); @@ -2862,6 +3109,15 @@ fn test_mint_to() { do_process_instruction( mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), vec![&mut mint_account, &mut account2_account, &mut owner_account], + &[ + Check::success(), + Check::account(&mint_key) + .data_slice(36, &84u64.to_le_bytes()) + .build(), + Check::account(&account2_key) + .data_slice(64, &42u64.to_le_bytes()) + .build(), + ], ) .unwrap(); @@ -2879,6 +3135,7 @@ fn test_mint_to() { do_process_instruction( instruction, vec![&mut mint_account, &mut account2_account, &mut owner_account], + &[Check::err(ProgramError::MissingRequiredSignature)], ) ); @@ -2888,6 +3145,7 @@ fn test_mint_to() { do_process_instruction( mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 42).unwrap(), vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + &[Check::err(TokenError::MintMismatch.into())], ) ); @@ -2901,6 +3159,7 @@ fn test_mint_to() { &mut account2_account, &mut owner2_account, ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -2912,6 +3171,7 @@ fn test_mint_to() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::err(ProgramError::IncorrectProgramId)], ) ); mint_account.owner = program_id; @@ -2924,6 +3184,7 @@ fn test_mint_to() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 0).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::err(ProgramError::IncorrectProgramId)], ) ); account_account.owner = program_id; @@ -2946,6 +3207,7 @@ fn test_mint_to() { &mut uninitialized_account, &mut owner_account, ], + &[Check::err(ProgramError::UninitializedAccount)], ) ); @@ -2961,6 +3223,7 @@ fn test_mint_to() { ) .unwrap(), vec![&mut mint_account, &mut owner_account], + &[Check::success()], ) .unwrap(); assert_eq!( @@ -2968,6 +3231,7 @@ fn test_mint_to() { do_process_instruction( mint_to(&program_id, &mint_key, &account2_key, &owner_key, &[], 42).unwrap(), vec![&mut mint_account, &mut account2_account, &mut owner_account], + &[Check::err(TokenError::FixedSupply.into())], ) ); } @@ -2997,6 +3261,7 @@ fn test_burn_dups() { do_process_instruction_dups( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![mint_info.clone(), rent_info.clone()], + &[Check::success()], ) .unwrap(); @@ -3009,6 +3274,7 @@ fn test_burn_dups() { account1_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -3016,6 +3282,7 @@ fn test_burn_dups() { do_process_instruction_dups( mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); @@ -3035,6 +3302,7 @@ fn test_burn_dups() { mint_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -3055,6 +3323,7 @@ fn test_burn_dups() { mint_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -3062,6 +3331,7 @@ fn test_burn_dups() { do_process_instruction_dups( mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); @@ -3070,6 +3340,7 @@ fn test_burn_dups() { do_process_instruction_dups( burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + &[Check::success()], ) .unwrap(); @@ -3086,6 +3357,7 @@ fn test_burn_dups() { ) .unwrap(), vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + &[Check::success()], ) .unwrap(); @@ -3093,6 +3365,7 @@ fn test_burn_dups() { do_process_instruction_dups( mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); @@ -3115,6 +3388,7 @@ fn test_burn_dups() { mint_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -3135,6 +3409,7 @@ fn test_burn_dups() { mint_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -3142,6 +3417,7 @@ fn test_burn_dups() { do_process_instruction_dups( mint_to(&program_id, &mint_key, &account1_key, &owner_key, &[], 1000).unwrap(), vec![mint_info.clone(), account1_info.clone(), owner_info.clone()], + &[Check::success()], ) .unwrap(); let mut account = Account::unpack_unchecked(&account1_info.data.borrow()).unwrap(); @@ -3152,6 +3428,7 @@ fn test_burn_dups() { do_process_instruction_dups( burn(&program_id, &account1_key, &mint_key, &mint_key, &[], 500).unwrap(), vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + &[Check::success()], ) .unwrap(); @@ -3168,6 +3445,7 @@ fn test_burn_dups() { ) .unwrap(), vec![account1_info.clone(), mint_info.clone(), mint_info.clone()], + &[Check::success()], ) .unwrap(); } @@ -3215,6 +3493,7 @@ fn test_burn() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -3227,6 +3506,7 @@ fn test_burn() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -3239,6 +3519,7 @@ fn test_burn() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -3251,6 +3532,7 @@ fn test_burn() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -3263,6 +3545,7 @@ fn test_burn() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -3270,6 +3553,7 @@ fn test_burn() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -3277,6 +3561,7 @@ fn test_burn() { do_process_instruction( mint_to(&program_id, &mint_key, &mismatch_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut mismatch_account, &mut owner_account], + &[Check::success()], ) .unwrap(); let mut account = Account::unpack_unchecked(&mismatch_account.data).unwrap(); @@ -3296,6 +3581,7 @@ fn test_burn() { &mut mint_account, &mut delegate_account ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -3305,6 +3591,7 @@ fn test_burn() { do_process_instruction( burn(&program_id, &account_key, &mint_key, &owner2_key, &[], 42).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner2_account], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -3316,6 +3603,7 @@ fn test_burn() { do_process_instruction( burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::err(ProgramError::IncorrectProgramId)], ) ); account_account.owner = program_id; @@ -3328,6 +3616,7 @@ fn test_burn() { do_process_instruction( burn(&program_id, &account_key, &mint_key, &owner_key, &[], 0).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::err(ProgramError::IncorrectProgramId)], ) ); mint_account.owner = program_id; @@ -3338,6 +3627,7 @@ fn test_burn() { do_process_instruction( burn(&program_id, &mismatch_key, &mint_key, &owner_key, &[], 42).unwrap(), vec![&mut mismatch_account, &mut mint_account, &mut owner_account], + &[Check::err(TokenError::MintMismatch.into())], ) ); @@ -3345,6 +3635,7 @@ fn test_burn() { do_process_instruction( burn(&program_id, &account_key, &mint_key, &owner_key, &[], 21).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -3354,6 +3645,7 @@ fn test_burn() { do_process_instruction( burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 3).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::err(TokenError::MintDecimalsMismatch.into())], ) ); @@ -3361,6 +3653,15 @@ fn test_burn() { do_process_instruction( burn_checked(&program_id, &account_key, &mint_key, &owner_key, &[], 21, 2).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[ + Check::success(), + Check::account(&mint_key) + .data_slice(36, &(2000u64 - 42).to_le_bytes()) + .build(), + Check::account(&account_key) + .data_slice(64, &(1000u64 - 42).to_le_bytes()) + .build(), + ], ) .unwrap(); @@ -3383,6 +3684,7 @@ fn test_burn() { ) .unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -3402,6 +3704,7 @@ fn test_burn() { &mut delegate_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -3419,6 +3722,7 @@ fn test_burn() { ) .unwrap(), vec![&mut account_account, &mut mint_account, &mut owner2_account], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -3432,6 +3736,7 @@ fn test_burn() { &mut mint_account, &mut delegate_account ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -3443,6 +3748,15 @@ fn test_burn() { &mut mint_account, &mut delegate_account, ], + &[ + Check::success(), + Check::account(&mint_key) + .data_slice(36, &(2000u64 - 42 - 84).to_le_bytes()) + .build(), + Check::account(&account_key) + .data_slice(64, &(1000u64 - 42 - 84).to_le_bytes()) + .build(), + ], ) .unwrap(); @@ -3462,6 +3776,7 @@ fn test_burn() { &mut mint_account, &mut delegate_account ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); } @@ -3500,6 +3815,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { do_process_instruction( initialize_mint2(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account], + &[Check::success()], ) .unwrap(); @@ -3507,6 +3823,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { do_process_instruction( initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), vec![&mut account_account, &mut mint_account], + &[Check::success()], ) .unwrap(); @@ -3520,6 +3837,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { ) .unwrap(), vec![&mut incinerator_account, &mut mint_account], + &[Check::success()], ) .unwrap(); do_process_instruction( @@ -3531,6 +3849,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { ) .unwrap(), vec![&mut system_account, &mut mint_account], + &[Check::success()], ) .unwrap(); @@ -3538,6 +3857,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -3557,6 +3877,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut incinerator_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); do_process_instruction( @@ -3574,6 +3895,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut system_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -3594,6 +3916,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut mock_incinerator_account, &mut owner_account, ], + &[Check::err(TokenError::NonNativeHasBalance.into())], ) ); assert_eq!( @@ -3612,6 +3935,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut mock_incinerator_account, &mut owner_account, ], + &[Check::err(TokenError::NonNativeHasBalance.into())], ) ); @@ -3631,6 +3955,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut mint_account, &mut recipient_account, ], + &[Check::success()], ) .unwrap(); do_process_instruction( @@ -3648,6 +3973,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut mint_account, &mut recipient_account, ], + &[Check::success()], ) .unwrap(); @@ -3668,6 +3994,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut recipient_account, &mut owner_account, ], + &[Check::err(ProgramError::InvalidAccountData)], ) ); assert_eq!( @@ -3686,6 +4013,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut recipient_account, &mut owner_account, ], + &[Check::err(ProgramError::InvalidAccountData)], ) ); @@ -3704,6 +4032,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut mock_incinerator_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); @@ -3721,6 +4050,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &mut mock_incinerator_account, &mut owner_account, ], + &[Check::success()], ) .unwrap(); } @@ -3769,6 +4099,7 @@ fn test_multisig() { &mut rent_sysvar, account_info_iter.next().unwrap(), ], + &[Check::err(TokenError::NotRentExempt.into())], ) ); @@ -3784,6 +4115,7 @@ fn test_multisig() { &mut rent_sysvar, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -3792,6 +4124,7 @@ fn test_multisig() { do_process_instruction( initialize_multisig2(&program_id, &multisig_key, &[&signer_keys[0]], 1).unwrap(), vec![&mut multisig_account2, account_info_iter.next().unwrap()], + &[Check::success()], ) .unwrap(); @@ -3820,6 +4153,7 @@ fn test_multisig() { account_info_iter.next().unwrap(), account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -3827,6 +4161,7 @@ fn test_multisig() { do_process_instruction( initialize_mint(&program_id, &mint_key, &multisig_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -3839,6 +4174,7 @@ fn test_multisig() { &mut multisig_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -3857,6 +4193,7 @@ fn test_multisig() { &mut multisig_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -3878,6 +4215,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -3899,6 +4237,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -3920,6 +4259,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -3951,6 +4291,7 @@ fn test_multisig() { account_info_iter.next().unwrap(), account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -3972,6 +4313,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -3993,6 +4335,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -4024,6 +4367,7 @@ fn test_multisig() { account_info_iter.next().unwrap(), account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -4047,6 +4391,7 @@ fn test_multisig() { ) .unwrap(), vec![&mut mint2_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); do_process_instruction( @@ -4057,6 +4402,7 @@ fn test_multisig() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); let account_info_iter = &mut signer_accounts.iter_mut(); @@ -4076,6 +4422,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); let account_info_iter = &mut signer_accounts.iter_mut(); @@ -4094,6 +4441,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -4114,6 +4462,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); @@ -4134,6 +4483,7 @@ fn test_multisig() { &mut multisig_account, account_info_iter.next().unwrap(), ], + &[Check::success()], ) .unwrap(); } @@ -4154,6 +4504,7 @@ fn test_owner_close_account_dups() { do_process_instruction_dups( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![mint_info.clone(), rent_info.clone()], + &[Check::success()], ) .unwrap(); @@ -4181,6 +4532,7 @@ fn test_owner_close_account_dups() { to_close_account_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -4199,6 +4551,10 @@ fn test_owner_close_account_dups() { destination_account_info.clone(), to_close_account_info.clone(), ], + &[ + Check::success(), + Check::account(&to_close_key).data(&[]).build(), + ], ) .unwrap(); assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); @@ -4220,6 +4576,7 @@ fn test_close_authority_close_account_dups() { do_process_instruction_dups( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![mint_info.clone(), rent_info.clone()], + &[Check::success()], ) .unwrap(); @@ -4247,6 +4604,7 @@ fn test_close_authority_close_account_dups() { to_close_account_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); let mut account = Account::unpack_unchecked(&to_close_account_info.data.borrow()).unwrap(); @@ -4267,6 +4625,10 @@ fn test_close_authority_close_account_dups() { destination_account_info.clone(), to_close_account_info.clone(), ], + &[ + Check::success(), + Check::account(&to_close_key).data(&[]).build(), + ], ) .unwrap(); assert_eq!(*to_close_account_info.data.borrow(), &[0u8; Account::LEN]); @@ -4312,6 +4674,7 @@ fn test_close_account() { &mut account3_account, &mut owner2_account, ], + &[Check::err(ProgramError::UninitializedAccount)], ) ); @@ -4319,6 +4682,7 @@ fn test_close_account() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); do_process_instruction( @@ -4329,6 +4693,7 @@ fn test_close_account() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); do_process_instruction( @@ -4339,6 +4704,12 @@ fn test_close_account() { &mut owner_account, &mut rent_sysvar, ], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &42u64.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -4359,6 +4730,15 @@ fn test_close_account() { &mut owner_account, &mut rent_sysvar, ], + &[ + Check::success(), + Check::account(&account2_key) + .data_slice(109, &[1, 0, 0, 0]) + .build(), + Check::account(&account2_key) + .data_slice(64, &42u64.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account2_account.data).unwrap(); @@ -4375,6 +4755,12 @@ fn test_close_account() { &mut account3_account, &mut owner_account, ], + &[ + Check::err(TokenError::NonNativeHasBalance.into()), + Check::account(&account_key) + .lamports(account_minimum_balance()) + .build() + ], ) ); assert_eq!(account_account.lamports, account_minimum_balance()); @@ -4383,6 +4769,7 @@ fn test_close_account() { do_process_instruction( burn(&program_id, &account_key, &mint_key, &owner_key, &[], 42).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -4396,6 +4783,7 @@ fn test_close_account() { &mut account3_account, &mut owner2_account, ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -4407,6 +4795,14 @@ fn test_close_account() { &mut account3_account, &mut owner_account, ], + &[ + Check::success(), + Check::account(&account_key).data(&[]).build(), + Check::account(&account_key).lamports(0).build(), + Check::account(&account3_key) + .lamports(2 * account_minimum_balance()) + .build(), + ], ) .unwrap(); assert!(account_account.data.is_empty()); @@ -4434,6 +4830,7 @@ fn test_close_account() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); account_account.lamports = 2; @@ -4449,6 +4846,7 @@ fn test_close_account() { ) .unwrap(), vec![&mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -4462,6 +4860,7 @@ fn test_close_account() { &mut account3_account, &mut owner_account, ], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -4473,6 +4872,14 @@ fn test_close_account() { &mut account3_account, &mut owner2_account, ], + &[ + Check::success(), + Check::account(&account_key).data(&[]).build(), + Check::account(&account_key).lamports(0).build(), + Check::account(&account3_key) + .lamports(2 * account_minimum_balance() + 2) + .build(), + ], ) .unwrap(); assert!(account_account.data.is_empty()); @@ -4487,6 +4894,13 @@ fn test_close_account() { &mut account3_account, &mut owner_account, ], + &[ + Check::success(), + Check::account(&account2_key).data(&[]).build(), + Check::account(&account3_key) + .lamports(3 * account_minimum_balance() + 2 + 42) + .build(), + ], ) .unwrap(); assert!(account2_account.data.is_empty()); @@ -4537,6 +4951,15 @@ fn test_native_token() { &mut owner_account, &mut rent_sysvar, ], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(109, &[1, 0, 0, 0]) + .build(), + Check::account(&account_key) + .data_slice(64, &40u64.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -4558,6 +4981,15 @@ fn test_native_token() { &mut owner_account, &mut rent_sysvar, ], + &[ + Check::success(), + Check::account(&account2_key) + .data_slice(109, &[1, 0, 0, 0]) + .build(), + Check::account(&account2_key) + .data_slice(64, &0u64.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account2_account.data).unwrap(); @@ -4578,6 +5010,7 @@ fn test_native_token() { ) .unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::err(TokenError::NativeNotSupported.into())], ) ); @@ -4588,6 +5021,7 @@ fn test_native_token() { do_process_instruction( initialize_mint(&program_id, &bogus_mint_key, &owner_key, None, 2).unwrap(), vec![&mut bogus_mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -4608,6 +5042,7 @@ fn test_native_token() { &mut bogus_mint_account, &mut owner_account ], + &[Check::err(TokenError::NativeNotSupported.into())], ) ); @@ -4629,6 +5064,7 @@ fn test_native_token() { &mut account2_account, &mut owner_account, ], + &[Check::err(TokenError::InsufficientFunds.into())], ) ); @@ -4648,6 +5084,27 @@ fn test_native_token() { &mut account2_account, &mut owner_account, ], + &[ + Check::success(), + Check::account(&account_key) + .lamports(account_minimum_balance()) + .build(), + Check::account(&account_key) + .data_slice(109, &[1, 0, 0, 0]) + .build(), + Check::account(&account_key) + .data_slice(64, &0u64.to_le_bytes()) + .build(), + Check::account(&account2_key) + .lamports(account_minimum_balance() + 40) + .build(), + Check::account(&account_key) + .data_slice(109, &[1, 0, 0, 0]) + .build(), + Check::account(&account2_key) + .data_slice(64, &40u64.to_le_bytes()) + .build(), + ], ) .unwrap(); assert_eq!(account_account.lamports, account_minimum_balance()); @@ -4671,6 +5128,15 @@ fn test_native_token() { ) .unwrap(), vec![&mut account_account, &mut owner_account], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(129, &[1, 0, 0, 0]) + .build(), + Check::account(&account_key) + .data_slice(133, owner3_key.as_ref()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -4688,6 +5154,12 @@ fn test_native_token() { ) .unwrap(), vec![&mut account_account, &mut owner_account], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(129, &[0, 0, 0, 0]) + .build(), + ], ) .unwrap(); @@ -4703,6 +5175,14 @@ fn test_native_token() { &mut account3_account, &mut owner2_account, ], + &[ + Check::success(), + Check::account(&account_key).lamports(0).build(), + Check::account(&account3_key) + .lamports(2 * account_minimum_balance()) + .build(), + Check::account(&account_key).data(&[]).build(), + ], ) .unwrap(); assert_eq!(account_account.lamports, 0); @@ -4740,6 +5220,7 @@ fn test_overflow() { do_process_instruction( initialize_mint(&program_id, &mint_key, &mint_owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -4752,6 +5233,7 @@ fn test_overflow() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -4764,6 +5246,7 @@ fn test_overflow() { &mut owner2_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -4783,6 +5266,12 @@ fn test_overflow() { &mut account_account, &mut mint_owner_account, ], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &u64::MAX.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -4806,6 +5295,12 @@ fn test_overflow() { &mut account_account, &mut mint_owner_account, ], + &[ + Check::err(TokenError::Overflow.into()), + Check::account(&account_key) + .data_slice(64, &u64::MAX.to_le_bytes()) + .build(), + ], ) ); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -4829,6 +5324,7 @@ fn test_overflow() { &mut account2_account, &mut mint_owner_account, ], + &[Check::err(TokenError::Overflow.into())], ) ); @@ -4836,6 +5332,12 @@ fn test_overflow() { do_process_instruction( burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &(u64::MAX - 100).to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -4856,6 +5358,12 @@ fn test_overflow() { &mut account_account, &mut mint_owner_account, ], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(64, &u64::MAX.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -4883,6 +5391,7 @@ fn test_overflow() { &mut account_account, &mut owner2_account, ], + &[Check::err(TokenError::Overflow.into())], ) ); } @@ -4913,6 +5422,7 @@ fn test_frozen() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -4925,6 +5435,7 @@ fn test_frozen() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -4937,6 +5448,7 @@ fn test_frozen() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -4944,6 +5456,7 @@ fn test_frozen() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -4968,6 +5481,7 @@ fn test_frozen() { &mut account2_account, &mut owner_account, ], + &[Check::err(TokenError::AccountFrozen.into())], ) ); @@ -4994,6 +5508,7 @@ fn test_frozen() { &mut account2_account, &mut owner_account, ], + &[Check::err(TokenError::AccountFrozen.into())], ) ); @@ -5020,6 +5535,7 @@ fn test_frozen() { &mut delegate_account, &mut owner_account, ], + &[Check::err(TokenError::AccountFrozen.into())], ) ); @@ -5033,6 +5549,7 @@ fn test_frozen() { do_process_instruction( revoke(&program_id, &account_key, &owner_key, &[]).unwrap(), vec![&mut account_account, &mut owner_account], + &[Check::err(TokenError::AccountFrozen.into())], ) ); @@ -5051,6 +5568,7 @@ fn test_frozen() { ) .unwrap(), vec![&mut account_account, &mut owner_account,], + &[Check::err(TokenError::AccountFrozen.into())], ) ); @@ -5060,6 +5578,7 @@ fn test_frozen() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 100).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account,], + &[Check::err(TokenError::AccountFrozen.into())], ) ); @@ -5069,6 +5588,7 @@ fn test_frozen() { do_process_instruction( burn(&program_id, &account_key, &mint_key, &owner_key, &[], 100).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::err(TokenError::AccountFrozen.into())], ) ); } @@ -5096,6 +5616,7 @@ fn test_freeze_thaw_dups() { do_process_instruction_dups( initialize_mint(&program_id, &mint_key, &owner_key, Some(&account1_key), 2).unwrap(), vec![mint_info.clone(), rent_info.clone()], + &[Check::success()], ) .unwrap(); @@ -5108,6 +5629,7 @@ fn test_freeze_thaw_dups() { account1_info.clone(), rent_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -5119,6 +5641,7 @@ fn test_freeze_thaw_dups() { mint_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); @@ -5133,6 +5656,7 @@ fn test_freeze_thaw_dups() { mint_info.clone(), account1_info.clone(), ], + &[Check::success()], ) .unwrap(); } @@ -5161,6 +5685,7 @@ fn test_freeze_account() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -5173,6 +5698,7 @@ fn test_freeze_account() { &mut account_owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -5180,6 +5706,7 @@ fn test_freeze_account() { do_process_instruction( mint_to(&program_id, &mint_key, &account_key, &owner_key, &[], 1000).unwrap(), vec![&mut mint_account, &mut account_account, &mut owner_account], + &[Check::success()], ) .unwrap(); @@ -5189,6 +5716,7 @@ fn test_freeze_account() { do_process_instruction( freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::err(TokenError::MintCannotFreeze.into())], ) ); @@ -5201,6 +5729,7 @@ fn test_freeze_account() { do_process_instruction( freeze_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner2_account], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -5210,6 +5739,7 @@ fn test_freeze_account() { do_process_instruction( thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner2_account], + &[Check::err(TokenError::InvalidState.into())], ) ); @@ -5217,6 +5747,12 @@ fn test_freeze_account() { do_process_instruction( freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(108, &[AccountState::Frozen as u8]) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -5228,6 +5764,7 @@ fn test_freeze_account() { do_process_instruction( freeze_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[Check::err(TokenError::InvalidState.into())], ) ); @@ -5237,6 +5774,7 @@ fn test_freeze_account() { do_process_instruction( thaw_account(&program_id, &account_key, &mint_key, &owner2_key, &[]).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner2_account], + &[Check::err(TokenError::OwnerMismatch.into())], ) ); @@ -5244,6 +5782,12 @@ fn test_freeze_account() { do_process_instruction( thaw_account(&program_id, &account_key, &mint_key, &owner_key, &[]).unwrap(), vec![&mut account_account, &mut mint_account, &mut owner_account], + &[ + Check::success(), + Check::account(&account_key) + .data_slice(108, &[AccountState::Initialized as u8]) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); @@ -5280,6 +5824,7 @@ fn test_initialize_account2_and_3() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -5291,12 +5836,14 @@ fn test_initialize_account2_and_3() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); do_process_instruction( initialize_account2(&program_id, &account_key, &mint_key, &owner_key).unwrap(), vec![&mut account2_account, &mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -5305,6 +5852,7 @@ fn test_initialize_account2_and_3() { do_process_instruction( initialize_account3(&program_id, &account_key, &mint_key, &owner_key).unwrap(), vec![&mut account3_account, &mut mint_account], + &[Check::success()], ) .unwrap(); @@ -5339,6 +5887,7 @@ fn test_sync_native() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -5351,6 +5900,15 @@ fn test_sync_native() { &mut owner_account, &mut rent_sysvar, ], + &[ + Check::success(), + Check::account(&non_native_account_key) + .data_slice(109, &[0, 0, 0, 0]) + .build(), + Check::account(&non_native_account_key) + .data_slice(64, &0u64.to_le_bytes()) + .build(), + ], ) .unwrap(); @@ -5364,6 +5922,7 @@ fn test_sync_native() { do_process_instruction( sync_native(&program_id, &non_native_account_key,).unwrap(), vec![&mut non_native_account], + &[Check::err(TokenError::NonNativeNotSupported.into())], ) ); @@ -5373,6 +5932,7 @@ fn test_sync_native() { do_process_instruction( sync_native(&program_id, &native_account_key,).unwrap(), vec![&mut native_account], + &[Check::err(ProgramError::UninitializedAccount)], ) ); @@ -5391,6 +5951,7 @@ fn test_sync_native() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -5402,6 +5963,15 @@ fn test_sync_native() { do_process_instruction( sync_native(&program_id, &native_account_key,).unwrap(), vec![&mut native_account], + &[ + Check::err(ProgramError::IncorrectProgramId), + Check::account(&native_account_key) + .data_slice(109, &[1, 0, 0, 0]) + .build(), + Check::account(&native_account_key) + .data_slice(64, &lamports.to_le_bytes()) + .build() + ], ) ); native_account.owner = program_id; @@ -5414,6 +5984,12 @@ fn test_sync_native() { do_process_instruction( sync_native(&program_id, &native_account_key).unwrap(), vec![&mut native_account], + &[ + Check::success(), + Check::account(&native_account_key) + .data_slice(64, &lamports.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&native_account.data).unwrap(); @@ -5427,6 +6003,12 @@ fn test_sync_native() { do_process_instruction( sync_native(&program_id, &native_account_key).unwrap(), vec![&mut native_account], + &[ + Check::success(), + Check::account(&native_account_key) + .data_slice(64, &new_lamports.to_le_bytes()) + .build(), + ], ) .unwrap(); let account = Account::unpack_unchecked(&native_account.data).unwrap(); @@ -5441,6 +6023,7 @@ fn test_sync_native() { do_process_instruction( sync_native(&program_id, &native_account_key,).unwrap(), vec![&mut native_account], + &[Check::err(TokenError::InvalidState.into())], ) ); } @@ -5461,19 +6044,24 @@ fn test_get_account_data_size() { do_process_instruction( get_account_data_size(&program_id, &mint_key).unwrap(), vec![&mut mint_account], + &[Check::err(TokenError::InvalidMint.into())], ) ); do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); - set_expected_data(Account::LEN.to_le_bytes().to_vec()); do_process_instruction( get_account_data_size(&program_id, &mint_key).unwrap(), vec![&mut mint_account], + &[ + Check::success(), + Check::return_data(&Account::LEN.to_le_bytes()), + ], ) .unwrap(); } @@ -5498,6 +6086,7 @@ fn test_initialize_immutable_owner() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); @@ -5505,6 +6094,7 @@ fn test_initialize_immutable_owner() { do_process_instruction( initialize_immutable_owner(&program_id, &account_key).unwrap(), vec![&mut account_account], + &[Check::success()], ) .unwrap(); @@ -5517,6 +6107,7 @@ fn test_initialize_immutable_owner() { &mut owner_account, &mut rent_sysvar, ], + &[Check::success()], ) .unwrap(); @@ -5526,6 +6117,7 @@ fn test_initialize_immutable_owner() { do_process_instruction( initialize_immutable_owner(&program_id, &account_key).unwrap(), vec![&mut account_account], + &[Check::err(TokenError::AlreadyInUse.into())], ) ); } @@ -5546,6 +6138,7 @@ fn test_amount_to_ui_amount() { do_process_instruction( amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), vec![&mut mint_account], + &[Check::err(TokenError::InvalidMint.into())], ) ); @@ -5553,34 +6146,35 @@ fn test_amount_to_ui_amount() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); - set_expected_data("0.23".as_bytes().to_vec()); do_process_instruction( amount_to_ui_amount(&program_id, &mint_key, 23).unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data("0.23".as_bytes())], ) .unwrap(); - set_expected_data("1.1".as_bytes().to_vec()); do_process_instruction( amount_to_ui_amount(&program_id, &mint_key, 110).unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data("1.1".as_bytes())], ) .unwrap(); - set_expected_data("42".as_bytes().to_vec()); do_process_instruction( amount_to_ui_amount(&program_id, &mint_key, 4200).unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data("42".as_bytes())], ) .unwrap(); - set_expected_data("0".as_bytes().to_vec()); do_process_instruction( amount_to_ui_amount(&program_id, &mint_key, 0).unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data("0".as_bytes())], ) .unwrap(); } @@ -5601,6 +6195,7 @@ fn test_ui_amount_to_amount() { do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), vec![&mut mint_account], + &[Check::err(TokenError::InvalidMint.into())], ) ); @@ -5608,69 +6203,70 @@ fn test_ui_amount_to_amount() { do_process_instruction( initialize_mint(&program_id, &mint_key, &owner_key, None, 2).unwrap(), vec![&mut mint_account, &mut rent_sysvar], + &[Check::success()], ) .unwrap(); - set_expected_data(23u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "0.23").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&23u64.to_le_bytes())], ) .unwrap(); - set_expected_data(20u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "0.20").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&20u64.to_le_bytes())], ) .unwrap(); - set_expected_data(20u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "0.2000").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&20u64.to_le_bytes())], ) .unwrap(); - set_expected_data(20u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, ".20").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&20u64.to_le_bytes())], ) .unwrap(); - set_expected_data(110u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "1.1").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&110u64.to_le_bytes())], ) .unwrap(); - set_expected_data(110u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "1.10").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&110u64.to_le_bytes())], ) .unwrap(); - set_expected_data(4200u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "42").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&4200u64.to_le_bytes())], ) .unwrap(); - set_expected_data(4200u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "42.").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&4200u64.to_le_bytes())], ) .unwrap(); - set_expected_data(0u64.to_le_bytes().to_vec()); do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "0").unwrap(), vec![&mut mint_account], + &[Check::success(), Check::return_data(&0u64.to_le_bytes())], ) .unwrap(); @@ -5680,6 +6276,7 @@ fn test_ui_amount_to_amount() { do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "").unwrap(), vec![&mut mint_account], + &[Check::err(ProgramError::InvalidArgument)], ) ); assert_eq!( @@ -5687,6 +6284,7 @@ fn test_ui_amount_to_amount() { do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, ".").unwrap(), vec![&mut mint_account], + &[Check::err(ProgramError::InvalidArgument)], ) ); assert_eq!( @@ -5694,6 +6292,7 @@ fn test_ui_amount_to_amount() { do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "0.111").unwrap(), vec![&mut mint_account], + &[Check::err(ProgramError::InvalidArgument)], ) ); assert_eq!( @@ -5701,6 +6300,7 @@ fn test_ui_amount_to_amount() { do_process_instruction( ui_amount_to_amount(&program_id, &mint_key, "0.t").unwrap(), vec![&mut mint_account], + &[Check::err(ProgramError::InvalidArgument)], ) ); } diff --git a/program/tests/setup.rs b/program/tests/setup.rs index df79381..4365dea 100644 --- a/program/tests/setup.rs +++ b/program/tests/setup.rs @@ -2,10 +2,7 @@ use { solana_sdk::{ - account::{Account as SolanaAccount, AccountSharedData}, - program_pack::Pack, - pubkey::Pubkey, - rent::Rent, + account::Account as SolanaAccount, program_pack::Pack, pubkey::Pubkey, rent::Rent, }, spl_token::state::{Account, AccountState, Mint}, }; @@ -15,7 +12,7 @@ pub fn setup_mint_account( freeze_authority: Option<&Pubkey>, supply: u64, decimals: u8, -) -> AccountSharedData { +) -> SolanaAccount { let data = { let mut data = vec![0; Mint::LEN]; let state = Mint { @@ -32,15 +29,15 @@ pub fn setup_mint_account( let space = data.len(); let lamports = Rent::default().minimum_balance(space); - AccountSharedData::from(SolanaAccount { + SolanaAccount { lamports, data, owner: spl_token::id(), ..Default::default() - }) + } } -pub fn setup_token_account(mint: &Pubkey, owner: &Pubkey, amount: u64) -> AccountSharedData { +pub fn setup_token_account(mint: &Pubkey, owner: &Pubkey, amount: u64) -> SolanaAccount { let data = { let mut data = vec![0; Account::LEN]; let state = Account { @@ -60,10 +57,10 @@ pub fn setup_token_account(mint: &Pubkey, owner: &Pubkey, amount: u64) -> Accoun let space = data.len(); let lamports = Rent::default().minimum_balance(space); - AccountSharedData::from(SolanaAccount { + SolanaAccount { lamports, data, owner: spl_token::id(), ..Default::default() - }) + } } From be8d45a6f460f386cc0091f67ee9d2a4a4f8b121 Mon Sep 17 00:00:00 2001 From: Jon C Date: Mon, 3 Feb 2025 12:18:48 +0100 Subject: [PATCH 263/335] Audit: Update openssl to 0.10.70 (#21) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80c8a52..71bb79d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1747,9 +1747,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" dependencies = [ "bitflags 2.8.0", "cfg-if", @@ -1773,9 +1773,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" dependencies = [ "cc", "libc", From ee0052c26656df3b2b2c6165db40e85113293a2d Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 3 Oct 2024 15:01:34 +0100 Subject: [PATCH 264/335] Initial version --- p-token/Cargo.toml | 29 ++++ p-token/README.md | 3 + p-token/keypair.json | 1 + p-token/src/entrypoint.rs | 63 ++++++++ p-token/src/error.rs | 61 ++++++++ p-token/src/lib.rs | 9 ++ p-token/src/native_mint.rs | 15 ++ p-token/src/processor/initialize_account.rs | 112 ++++++++++++++ p-token/src/processor/initialize_mint.rs | 101 +++++++++++++ p-token/src/processor/mint_to.rs | 71 +++++++++ p-token/src/processor/mod.rs | 66 ++++++++ p-token/src/processor/transfer.rs | 158 ++++++++++++++++++++ p-token/src/state/account.rs | 88 +++++++++++ p-token/src/state/mint.rs | 27 ++++ p-token/src/state/mod.rs | 118 +++++++++++++++ p-token/src/state/multisignature.rs | 27 ++++ p-token/tests/initialize_account.rs | 93 ++++++++++++ p-token/tests/initialize_mint.rs | 83 ++++++++++ p-token/tests/mint_to.rs | 77 ++++++++++ p-token/tests/setup/account.rs | 43 ++++++ p-token/tests/setup/mint.rs | 84 +++++++++++ p-token/tests/setup/mod.rs | 4 + p-token/tests/transfer.rs | 94 ++++++++++++ 23 files changed, 1427 insertions(+) create mode 100644 p-token/Cargo.toml create mode 100644 p-token/README.md create mode 100644 p-token/keypair.json create mode 100644 p-token/src/entrypoint.rs create mode 100644 p-token/src/error.rs create mode 100644 p-token/src/lib.rs create mode 100644 p-token/src/native_mint.rs create mode 100644 p-token/src/processor/initialize_account.rs create mode 100644 p-token/src/processor/initialize_mint.rs create mode 100644 p-token/src/processor/mint_to.rs create mode 100644 p-token/src/processor/mod.rs create mode 100644 p-token/src/processor/transfer.rs create mode 100644 p-token/src/state/account.rs create mode 100644 p-token/src/state/mint.rs create mode 100644 p-token/src/state/mod.rs create mode 100644 p-token/src/state/multisignature.rs create mode 100644 p-token/tests/initialize_account.rs create mode 100644 p-token/tests/initialize_mint.rs create mode 100644 p-token/tests/mint_to.rs create mode 100644 p-token/tests/setup/account.rs create mode 100644 p-token/tests/setup/mint.rs create mode 100644 p-token/tests/setup/mod.rs create mode 100644 p-token/tests/transfer.rs diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml new file mode 100644 index 0000000..8bd475e --- /dev/null +++ b/p-token/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "token-program" +version = "0.0.0" +edition = "2021" +readme = "./README.md" +license-file = "../LICENSE" +publish = false + +[package.metadata.solana] +program-id = "TokenLight111111111111111111111111111111111" + +[lib] +crate-type = ["cdylib", "lib"] + +[features] +logging = [] +test-sbf = [] + +[dependencies] +bytemuck = { version="1.18.0", features=["derive"] } +pinocchio = { version="0.2", path="/Users/febo/Developer/febo/pinocchio/sdk/pinocchio" } +pinocchio-pubkey = "0.1" + +[dev-dependencies] +assert_matches = "1.5.0" +solana-program-test = "~1.18" +solana-sdk = "~1.18" +spl-token = { version="^4", features=["no-entrypoint"] } +test-case = "3.3.1" \ No newline at end of file diff --git a/p-token/README.md b/p-token/README.md new file mode 100644 index 0000000..987b9d8 --- /dev/null +++ b/p-token/README.md @@ -0,0 +1,3 @@ +# Token + +Your generated Solana program. Have fun! diff --git a/p-token/keypair.json b/p-token/keypair.json new file mode 100644 index 0000000..3092538 --- /dev/null +++ b/p-token/keypair.json @@ -0,0 +1 @@ +[178,215,114,55,146,0,60,153,90,63,112,26,148,148,111,230,196,181,5,124,14,237,142,43,207,114,102,60,145,103,53,23,249,192,123,198,160,247,138,44,243,38,29,240,233,86,143,132,170,26,154,207,174,195,147,223,12,231,253,195,118,55,207,100] \ No newline at end of file diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs new file mode 100644 index 0000000..a569c7a --- /dev/null +++ b/p-token/src/entrypoint.rs @@ -0,0 +1,63 @@ +use pinocchio::{ + account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, program_error::ProgramError, + pubkey::Pubkey, +}; + +use crate::processor::{ + initialize_account::process_initialize_account, + initialize_mint::{process_initialize_mint, InitializeMint}, + mint_to::process_mint_to, + transfer::process_transfer, +}; + +entrypoint!(process_instruction); + +#[inline(always)] +pub fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + match instruction_data.split_first() { + // 0 - InitializeMint + Some((&0, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeMint"); + + let instruction = InitializeMint::try_from_bytes(data)?; + process_initialize_mint(accounts, &instruction, true) + } + // 1 - InitializeAccount + Some((&1, _)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeAccount"); + + process_initialize_account(program_id, accounts, None, true) + } + // 3 - Transfer + Some((&3, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: Transfer"); + + let amount = u64::from_le_bytes( + data.try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + process_transfer(program_id, accounts, amount, None) + } + // 7 - InitializeMint + Some((&7, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: MintTo"); + + let amount = u64::from_le_bytes( + data.try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + process_mint_to(program_id, accounts, amount, None) + } + _ => Err(ProgramError::InvalidInstructionData), + } +} diff --git a/p-token/src/error.rs b/p-token/src/error.rs new file mode 100644 index 0000000..68b669e --- /dev/null +++ b/p-token/src/error.rs @@ -0,0 +1,61 @@ +//! Error types + +use pinocchio::program_error::ProgramError; + +/// Errors that may be returned by the Token program. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum TokenError { + // 0 + /// Lamport balance below rent-exempt threshold. + NotRentExempt, + /// Insufficient funds for the operation requested. + InsufficientFunds, + /// Invalid Mint. + InvalidMint, + /// Account not associated with this Mint. + MintMismatch, + /// Owner does not match. + OwnerMismatch, + + // 5 + /// This token's supply is fixed and new tokens cannot be minted. + FixedSupply, + /// The account cannot be initialized because it is already being used. + AlreadyInUse, + /// Invalid number of provided signers. + InvalidNumberOfProvidedSigners, + /// Invalid number of required signers. + InvalidNumberOfRequiredSigners, + /// State is uninitialized. + UninitializedState, + + // 10 + /// Instruction does not support native tokens + NativeNotSupported, + /// Non-native account can only be closed if its balance is zero + NonNativeHasBalance, + /// Invalid instruction + InvalidInstruction, + /// State is invalid for requested operation. + InvalidState, + /// Operation overflowed + Overflow, + + // 15 + /// Account does not support specified authority type. + AuthorityTypeNotSupported, + /// This token mint cannot freeze accounts. + MintCannotFreeze, + /// Account is frozen; all account operations will fail + AccountFrozen, + /// Mint decimals mismatch between the client and mint + MintDecimalsMismatch, + /// Instruction does not support non-native tokens + NonNativeNotSupported, +} + +impl From for ProgramError { + fn from(e: TokenError) -> Self { + ProgramError::Custom(e as u32) + } +} diff --git a/p-token/src/lib.rs b/p-token/src/lib.rs new file mode 100644 index 0000000..7c28f42 --- /dev/null +++ b/p-token/src/lib.rs @@ -0,0 +1,9 @@ +//! A lighter Token program for SVM. + +mod entrypoint; +pub mod error; +pub mod native_mint; +mod processor; +pub mod state; + +pinocchio_pubkey::declare_id!("TokenLight111111111111111111111111111111111"); diff --git a/p-token/src/native_mint.rs b/p-token/src/native_mint.rs new file mode 100644 index 0000000..eb8073e --- /dev/null +++ b/p-token/src/native_mint.rs @@ -0,0 +1,15 @@ +//! The Mint that represents the native token. + +use pinocchio::pubkey::Pubkey; + +/// There are 10^9 lamports in one SOL +pub const DECIMALS: u8 = 9; + +// The Mint for native SOL Token accounts +pub const ID: Pubkey = + pinocchio_pubkey::declare_pubkey!("So11111111111111111111111111111111111111112"); + +#[inline(always)] +pub fn is_native_mint(mint: &Pubkey) -> bool { + mint == &ID +} diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs new file mode 100644 index 0000000..7edfa2f --- /dev/null +++ b/p-token/src/processor/initialize_account.rs @@ -0,0 +1,112 @@ +use std::mem::size_of; + +use bytemuck::{Pod, Zeroable}; +use pinocchio::{ + account_info::AccountInfo, + entrypoint::ProgramResult, + get_account_info, + program_error::ProgramError, + pubkey::{self, Pubkey}, + sysvars::{rent::Rent, Sysvar}, +}; + +use crate::{ + error::TokenError, + native_mint::is_native_mint, + state::{ + account::{Account, AccountState}, + mint::Mint, + PodCOption, + }, +}; + +use super::check_account_owner; + +pub fn process_initialize_account( + program_id: &Pubkey, + accounts: &[AccountInfo], + args: Option<&InitializeAccount>, + _rent_sysvar_account: bool, +) -> ProgramResult { + let [new_account_info, mint_info, _remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + let owner = if let Some(InitializeAccount { owner }) = args { + owner + } else { + get_account_info!(accounts, 2).key() + }; + + // FEBO: ~408 CU can be saved by removing the rent check (is_exempt seems to + // be very expensive). + // + // The transaction will naturally fail if the account is not rent exempt with + // a TransactionError::InsufficientFundsForRent error. + /* + let rent = Rent::get()?; + + if !rent.is_exempt( + unsafe { *new_account_info.unchecked_borrow_lamports() }, + size_of::(), + ) { + return Err(Token::NotRentExempt); + } + */ + + let account_data = unsafe { new_account_info.unchecked_borrow_mut_data() }; + let account = bytemuck::try_from_bytes_mut::(account_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if account.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } + + let is_native_mint = is_native_mint(mint_info.key()); + + if !is_native_mint { + check_account_owner(program_id, mint_info)?; + + let mint_data = unsafe { mint_info.unchecked_borrow_data() }; + let mint = bytemuck::from_bytes::(mint_data); + + let initialized: bool = mint.is_initialized.into(); + if !initialized { + return Err(TokenError::InvalidMint.into()); + } + } + + pubkey::copy(&mut account.mint, mint_info.key()); + pubkey::copy(&mut account.owner, owner); + account.close_authority = PodCOption::from(None); + account.delegate = PodCOption::from(None); + account.delegated_amount = 0u64.to_le_bytes(); + account.state = AccountState::Initialized as u8; + + if is_native_mint { + let rent = Rent::get()?; + let rent_exempt_reserve = rent.minimum_balance(size_of::()); + + account.is_native = PodCOption::from(Some(rent_exempt_reserve.to_le_bytes())); + unsafe { + account.amount = new_account_info + .unchecked_borrow_lamports() + .checked_sub(rent_exempt_reserve) + .ok_or(TokenError::Overflow)? + .to_le_bytes() + } + } else { + account.is_native = PodCOption::from(None); + account.amount = 0u64.to_le_bytes(); + }; + + Ok(()) +} + +/// Instruction data for the `InitializeAccount` instruction. +#[repr(C)] +#[derive(Clone, Copy, Default, Pod, Zeroable)] +pub struct InitializeAccount { + /// The new account's owner/multisignature. + pub owner: Pubkey, +} diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs new file mode 100644 index 0000000..36c7f64 --- /dev/null +++ b/p-token/src/processor/initialize_mint.rs @@ -0,0 +1,101 @@ +use std::mem::size_of; + +use bytemuck::{Pod, Zeroable}; +use pinocchio::{ + account_info::AccountInfo, + entrypoint::ProgramResult, + program_error::ProgramError, + pubkey::{Pubkey, PUBKEY_BYTES}, +}; + +use crate::{ + error::TokenError, + state::{mint::Mint, PodCOption}, +}; + +pub fn process_initialize_mint( + accounts: &[AccountInfo], + args: &InitializeMint, + _rent_sysvar_account: bool, +) -> ProgramResult { + let [mint_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + let mint_data = &mut mint_info.try_borrow_mut_data()?; + let mint = bytemuck::from_bytes_mut::(mint_data); + + if mint.is_initialized.into() { + return Err(TokenError::AlreadyInUse.into()); + } + + // FEBO: ~408 CU can be saved by removing the rent check (is_exempt seems to + // be very expensive). + // + // The transaction will naturally fail if the account is not rent exempt with + // a TransactionError::InsufficientFundsForRent error. + /* + let rent = Rent::get()?; + + if !rent.is_exempt( + unsafe { *mint_info.unchecked_borrow_lamports() }, + size_of::(), + ) { + return Err(TokenError::NotRentExempt); + } + */ + + mint.mint_authority = PodCOption::from(Some(args.data.mint_authority)); + mint.decimals = args.data.decimals; + mint.is_initialized = true.into(); + + if let Some(freeze_authority) = args.freeze_authority { + mint.freeze_authority = PodCOption::from(Some(*freeze_authority)); + } + + Ok(()) +} + +/// Instruction data for the `InitializeMint` instruction. +pub struct InitializeMint<'a> { + pub data: &'a MintData, + + /// The freeze authority/multisignature of the mint. + pub freeze_authority: Option<&'a Pubkey>, +} + +impl<'a> InitializeMint<'a> { + pub fn try_from_bytes(data: &'a [u8]) -> Result { + // We expect the data to be at least the size of the MintInput struct + // plus one byte for the freeze_authority option. + if data.len() <= size_of::() { + return Err(ProgramError::InvalidInstructionData); + } + + let (data, remaining) = data.split_at(size_of::()); + let data = bytemuck::from_bytes::(data); + + let freeze_authority = match remaining.split_first() { + Some((&0, _)) => None, + Some((&1, pubkey)) if pubkey.len() == PUBKEY_BYTES => { + Some(bytemuck::from_bytes::(pubkey)) + } + _ => return Err(ProgramError::InvalidInstructionData), + }; + + Ok(Self { + data, + freeze_authority, + }) + } +} + +#[repr(C)] +#[derive(Clone, Copy, Default, Pod, Zeroable)] +pub struct MintData { + /// Number of base 10 digits to the right of the decimal place. + pub decimals: u8, + + /// The authority/multisignature to mint tokens. + pub mint_authority: Pubkey, +} diff --git a/p-token/src/processor/mint_to.rs b/p-token/src/processor/mint_to.rs new file mode 100644 index 0000000..4ce72cc --- /dev/null +++ b/p-token/src/processor/mint_to.rs @@ -0,0 +1,71 @@ +use pinocchio::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, + pubkey::Pubkey, +}; + +use crate::{ + error::TokenError, + native_mint::is_native_mint, + state::{account::Account, mint::Mint}, +}; + +use super::{check_account_owner, validate_owner}; + +pub fn process_mint_to( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + expected_decimals: Option, +) -> ProgramResult { + let [mint_info, destination_account_info, owner_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + // destination account + + let account_data = unsafe { destination_account_info.unchecked_borrow_mut_data() }; + let destination_account = bytemuck::from_bytes_mut::(account_data); + + if destination_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + if is_native_mint(mint_info.key()) { + return Err(TokenError::NativeNotSupported.into()); + } + + if mint_info.key() != &destination_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mint_data = unsafe { mint_info.unchecked_borrow_mut_data() }; + let mint = bytemuck::from_bytes_mut::(mint_data); + + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + match mint.mint_authority.get() { + Some(mint_authority) => validate_owner(program_id, &mint_authority, owner_info, remaining)?, + None => return Err(TokenError::FixedSupply.into()), + } + + if amount == 0 { + check_account_owner(program_id, mint_info)?; + check_account_owner(program_id, destination_account_info)?; + } + + let destination_amount = u64::from_le_bytes(destination_account.amount) + .checked_add(amount) + .ok_or(ProgramError::InvalidAccountData)?; + destination_account.amount = destination_amount.to_le_bytes(); + + let mint_supply = u64::from_le_bytes(mint.supply) + .checked_add(amount) + .ok_or(ProgramError::InvalidAccountData)?; + mint.supply = mint_supply.to_le_bytes(); + + Ok(()) +} diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs new file mode 100644 index 0000000..98cd433 --- /dev/null +++ b/p-token/src/processor/mod.rs @@ -0,0 +1,66 @@ +use pinocchio::{ + account_info::AccountInfo, + entrypoint::ProgramResult, + program_error::ProgramError, + pubkey::{self, Pubkey}, +}; + +use crate::{ + error::TokenError, + state::multisignature::{Multisig, MAX_SIGNERS}, +}; + +pub mod initialize_account; +pub mod initialize_mint; +pub mod mint_to; +pub mod transfer; + +/// Checks that the account is owned by the expected program. +#[inline(always)] +pub fn check_account_owner(program_id: &Pubkey, account_info: &AccountInfo) -> ProgramResult { + if program_id != account_info.owner() { + Err(ProgramError::IncorrectProgramId) + } else { + Ok(()) + } +} + +/// Validates owner(s) are present +#[inline(always)] +pub fn validate_owner( + program_id: &Pubkey, + expected_owner: &Pubkey, + owner_account_info: &AccountInfo, + signers: &[AccountInfo], +) -> ProgramResult { + if expected_owner != owner_account_info.key() { + return Err(TokenError::OwnerMismatch.into()); + } + + if owner_account_info.data_len() == Multisig::LEN && program_id != owner_account_info.owner() { + let multisig_data = owner_account_info.try_borrow_data()?; + let multisig = bytemuck::from_bytes::(&multisig_data); + + let mut num_signers = 0; + let mut matched = [false; MAX_SIGNERS]; + + for signer in signers.iter() { + for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() { + if pubkey::compare(key, signer.key()) && !matched[position] { + if !signer.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + matched[position] = true; + num_signers += 1; + } + } + } + if num_signers < multisig.m { + return Err(ProgramError::MissingRequiredSignature); + } + } else if !owner_account_info.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + + Ok(()) +} diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs new file mode 100644 index 0000000..7fe88ca --- /dev/null +++ b/p-token/src/processor/transfer.rs @@ -0,0 +1,158 @@ +use pinocchio::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, + pubkey::Pubkey, +}; + +use crate::{ + error::TokenError, + native_mint::is_native_mint, + state::{account::Account, mint::Mint, PodCOption}, +}; + +use super::{check_account_owner, validate_owner}; + +pub fn process_transfer( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + expected_decimals: Option, +) -> ProgramResult { + // Accounts expected depends on whether we have the mint `decimals` or not; when we have the + // mint `decimals`, we expect the mint account to be present. + + let ( + source_account_info, + expected_mint_info, + destination_account_info, + authority_info, + remaning, + ) = if let Some(decimals) = expected_decimals { + let [source_account_info, mint_info, destination_account_info, authority_info, remaning @ ..] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + ( + source_account_info, + Some((mint_info, decimals)), + destination_account_info, + authority_info, + remaning, + ) + } else { + let [source_account_info, destination_account_info, authority_info, remaning @ ..] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + ( + source_account_info, + None, + destination_account_info, + authority_info, + remaning, + ) + }; + + // Validates source and destination accounts. + + let source_account_data = unsafe { source_account_info.unchecked_borrow_mut_data() }; + let source_account = bytemuck::from_bytes_mut::(source_account_data); + + let destination_account_data = unsafe { destination_account_info.unchecked_borrow_mut_data() }; + let destination_account = bytemuck::from_bytes_mut::(destination_account_data); + + if source_account.is_frozen() || destination_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + // FEBO: Implicitly validates that the account has enough tokens by calculating the + // remaining amount. The amount is only updated on the account if the transfer + // is successful. + let remaining_amount = u64::from_le_bytes(source_account.amount) + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + + if source_account.mint != destination_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + // Validates the mint information. + + if let Some((mint_info, decimals)) = expected_mint_info { + if mint_info.key() != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mint_data = mint_info.try_borrow_data()?; + let mint = bytemuck::from_bytes::(&mint_data); + + if decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + let self_transfer = source_account_info.key() == destination_account_info.key(); + + // Validates the authority (delegate or owner). + + if source_account.delegate.as_ref() == Some(authority_info.key()) { + validate_owner(program_id, authority_info.key(), authority_info, remaning)?; + + let delegated_amount = u64::from_le_bytes(source_account.delegated_amount) + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + + if !self_transfer { + source_account.delegated_amount = delegated_amount.to_le_bytes(); + + if delegated_amount == 0 { + source_account.delegate = PodCOption::from(None); + } + } + } else { + validate_owner(program_id, &source_account.owner, authority_info, remaning)?; + } + + if self_transfer || amount == 0 { + check_account_owner(program_id, source_account_info)?; + check_account_owner(program_id, destination_account_info)?; + + // No need to move tokens around. + return Ok(()); + } + + // FEBO: This was moved to the if statement above since we can skip the amount + // manipulation if it is a self-transfer or the amount is zero. + // + // This check MUST occur just before the amounts are manipulated + // to ensure self-transfers are fully validated + /* + if self_transfer { + return Ok(()); + } + */ + + // Moves the tokens. + + source_account.amount = remaining_amount.to_le_bytes(); + + let destination_amount = u64::from_le_bytes(destination_account.amount) + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + destination_account.amount = destination_amount.to_le_bytes(); + + if is_native_mint(&source_account.mint) { + let mut source_lamports = source_account_info.try_borrow_mut_lamports()?; + *source_lamports = source_lamports + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + + let mut destination_lamports = destination_account_info.try_borrow_mut_lamports()?; + *destination_lamports = destination_lamports + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + } + + Ok(()) +} diff --git a/p-token/src/state/account.rs b/p-token/src/state/account.rs new file mode 100644 index 0000000..8b80209 --- /dev/null +++ b/p-token/src/state/account.rs @@ -0,0 +1,88 @@ +use bytemuck::{Pod, Zeroable}; +use pinocchio::pubkey::Pubkey; + +use super::PodCOption; + +/// Account data. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] +pub struct Account { + /// The mint associated with this account + pub mint: Pubkey, + + /// The owner of this account. + pub owner: Pubkey, + + /// The amount of tokens this account holds. + pub amount: [u8; 8], + + /// If `delegate` is `Some` then `delegated_amount` represents + /// the amount authorized by the delegate + pub delegate: PodCOption, + + /// The account's state + pub state: u8, + + /// If is_native.is_some, this is a native token, and the value logs the + /// rent-exempt reserve. An Account is required to be rent-exempt, so + /// the value is used by the Processor to ensure that wrapped SOL + /// accounts do not drop below this threshold. + pub is_native: PodCOption<[u8; 8]>, + + /// The amount delegated + pub delegated_amount: [u8; 8], + + /// Optional authority to close the account. + pub close_authority: PodCOption, +} + +impl Account { + #[inline] + pub fn is_initialized(&self) -> bool { + self.state != AccountState::Uninitialized as u8 + } + + #[inline] + pub fn is_frozen(&self) -> bool { + self.state == AccountState::Frozen as u8 + } +} + +/// Account state. +#[repr(u8)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub enum AccountState { + /// Account is not yet initialized + #[default] + Uninitialized, + + /// Account is initialized; the account owner and/or delegate may perform + /// permitted operations on this account + Initialized, + + /// Account has been frozen by the mint freeze authority. Neither the + /// account owner nor the delegate are able to perform operations on + /// this account. + Frozen, +} + +impl From for AccountState { + fn from(value: u8) -> Self { + match value { + 0 => AccountState::Uninitialized, + 1 => AccountState::Initialized, + 2 => AccountState::Frozen, + _ => panic!("invalid account state value: {value}"), + } + } +} + +impl From for u8 { + fn from(value: AccountState) -> Self { + match value { + AccountState::Uninitialized => 0, + AccountState::Initialized => 1, + AccountState::Frozen => 2, + } + } +} diff --git a/p-token/src/state/mint.rs b/p-token/src/state/mint.rs new file mode 100644 index 0000000..84e9c8e --- /dev/null +++ b/p-token/src/state/mint.rs @@ -0,0 +1,27 @@ +use bytemuck::{Pod, Zeroable}; +use pinocchio::pubkey::Pubkey; + +use super::{PodBool, PodCOption}; + +/// Mint data. +#[repr(C)] +#[derive(Clone, Copy, Default, Pod, Zeroable)] +pub struct Mint { + /// Optional authority used to mint new tokens. The mint authority may only + /// be provided during mint creation. If no mint authority is present + /// then the mint has a fixed supply and no further tokens may be + /// minted. + pub mint_authority: PodCOption, + + /// Total supply of tokens. + pub supply: [u8; 8], + + /// Number of base 10 digits to the right of the decimal place. + pub decimals: u8, + + /// Is `true` if this structure has been initialized + pub is_initialized: PodBool, + + /// Optional authority to freeze token accounts. + pub freeze_authority: PodCOption, +} diff --git a/p-token/src/state/mod.rs b/p-token/src/state/mod.rs new file mode 100644 index 0000000..3f48173 --- /dev/null +++ b/p-token/src/state/mod.rs @@ -0,0 +1,118 @@ +use std::mem::align_of; + +use bytemuck::{Pod, Zeroable}; + +pub mod account; +pub mod mint; +pub mod multisignature; + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct PodCOption { + /// Indicates if the option is `Some` or `None`. + tag: [u8; 4], + + /// The value of the option. + value: T, +} + +impl From> for PodCOption { + fn from(value: Option) -> Self { + if align_of::() != 1 { + panic!("PodCOption only supports Pod types with alignment 1"); + } + + match value { + Some(value) => Self { + tag: [1, 0, 0, 0], + value, + }, + None => Self { + tag: [0, 0, 0, 0], + value: T::default(), + }, + } + } +} + +impl PodCOption { + /// Returns `true` if the option is a `None` value. + #[inline] + pub fn is_none(&self) -> bool { + self.tag == [0, 0, 0, 0] + } + + /// Returns `true` if the option is a `Some` value. + #[inline] + pub fn is_some(&self) -> bool { + !self.is_none() + } + + /// Returns the contained value as an `Option`. + #[inline] + pub fn get(self) -> Option { + if self.is_none() { + None + } else { + Some(self.value) + } + } + + /// Returns the contained value as an `Option`. + #[inline] + pub fn as_ref(&self) -> Option<&T> { + if self.is_none() { + None + } else { + Some(&self.value) + } + } + + /// Returns the contained value as a mutable `Option`. + #[inline] + pub fn as_mut(&mut self) -> Option<&mut T> { + if self.is_none() { + None + } else { + Some(&mut self.value) + } + } +} + +/// ## Safety +/// +/// `PodCOption` requires a `Pod` type `T` with alignment of 1. +unsafe impl Pod for PodCOption {} + +/// ## Safety +/// +/// `PodCOption` requires a `Pod` type `T` with alignment of 1. +unsafe impl Zeroable for PodCOption {} + +#[repr(C)] +#[derive(Copy, Clone, Default, Pod, Zeroable)] +pub struct PodBool(u8); + +impl From for PodBool { + fn from(b: bool) -> Self { + Self(b.into()) + } +} + +impl From<&bool> for PodBool { + fn from(b: &bool) -> Self { + Self((*b).into()) + } +} + +impl From<&PodBool> for bool { + fn from(b: &PodBool) -> Self { + b.0 != 0 + } +} + +impl From for bool { + fn from(b: PodBool) -> Self { + b.0 != 0 + } +} diff --git a/p-token/src/state/multisignature.rs b/p-token/src/state/multisignature.rs new file mode 100644 index 0000000..4bf8a20 --- /dev/null +++ b/p-token/src/state/multisignature.rs @@ -0,0 +1,27 @@ +use bytemuck::{Pod, Zeroable}; +use pinocchio::pubkey::Pubkey; + +use super::PodBool; + +/// Minimum number of multisignature signers (min N) +pub const MIN_SIGNERS: usize = 1; +/// Maximum number of multisignature signers (max N) +pub const MAX_SIGNERS: usize = 11; + +/// Multisignature data. +#[repr(C)] +#[derive(Clone, Copy, Default, Pod, Zeroable)] +pub struct Multisig { + /// Number of signers required + pub m: u8, + /// Number of valid signers + pub n: u8, + /// Is `true` if this structure has been initialized + pub is_initialized: PodBool, + /// Signer public keys + pub signers: [Pubkey; MAX_SIGNERS], +} + +impl Multisig { + pub const LEN: usize = core::mem::size_of::(); +} diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs new file mode 100644 index 0000000..5172b4c --- /dev/null +++ b/p-token/tests/initialize_account.rs @@ -0,0 +1,93 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::mint; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] +#[tokio::test] +async fn initialize_account(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority, + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // Given a mint authority, freeze authority and an account keypair. + + let owner = Pubkey::new_unique(); + let account = Keypair::new(); + + let account_size = 165; + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_account( + &spl_token::ID, + &account.pubkey(), + &mint, + &owner, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new mint account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size), + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(!account.is_frozen()); + assert!(account.owner == owner); + assert!(account.mint == mint); +} diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs new file mode 100644 index 0000000..10194d3 --- /dev/null +++ b/p-token/tests/initialize_mint.rs @@ -0,0 +1,83 @@ +#![cfg(feature = "test-sbf")] + +use std::mem::size_of; + +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_option::COption, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; +use token_program::state::mint::Mint; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] +#[tokio::test] +async fn initialize_mint(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint authority, freeze authority and an account keypair. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + let account = Keypair::new(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_mint( + &spl_token::ID, + &account.pubkey(), + &mint_authority, + Some(&freeze_authority), + 0, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new mint account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size), + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let mint = spl_token::state::Mint::unpack(&account.data).unwrap(); + + assert!(mint.is_initialized); + assert!(mint.mint_authority == COption::Some(mint_authority)); + assert!(mint.freeze_authority == COption::Some(freeze_authority)); + assert!(mint.decimals == 0) +} diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs new file mode 100644 index 0000000..897b45d --- /dev/null +++ b/p-token/tests/mint_to.rs @@ -0,0 +1,77 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] +#[tokio::test] +async fn mint_to(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program) + .await + .unwrap(); + + // When we mint tokens to it. + + let mut mint_ix = spl_token::instruction::mint_to( + &spl_token::ID, + &mint, + &account, + &mint_authority.pubkey(), + &[], + 100, + ) + .unwrap(); + // Switches the program id to the token program. + mint_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[mint_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &mint_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.amount == 100); +} diff --git a/p-token/tests/setup/account.rs b/p-token/tests/setup/account.rs new file mode 100644 index 0000000..d43d94f --- /dev/null +++ b/p-token/tests/setup/account.rs @@ -0,0 +1,43 @@ +use solana_program_test::ProgramTestContext; +use solana_sdk::{ + program_error::ProgramError, pubkey::Pubkey, signature::Keypair, signer::Signer, + system_instruction, transaction::Transaction, +}; + +pub async fn initialize( + context: &mut ProgramTestContext, + mint: &Pubkey, + owner: &Pubkey, + program_id: &Pubkey, +) -> Result { + let account = Keypair::new(); + + let account_size = 165; + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = + spl_token::instruction::initialize_account(&spl_token::ID, &account.pubkey(), mint, owner) + .unwrap(); + initialize_ix.program_id = *program_id; + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size), + account_size as u64, + program_id, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + Ok(account.pubkey()) +} diff --git a/p-token/tests/setup/mint.rs b/p-token/tests/setup/mint.rs new file mode 100644 index 0000000..d428c68 --- /dev/null +++ b/p-token/tests/setup/mint.rs @@ -0,0 +1,84 @@ +use std::mem::size_of; + +use solana_program_test::{BanksClientError, ProgramTestContext}; +use solana_sdk::{ + program_error::ProgramError, pubkey::Pubkey, signature::Keypair, signer::Signer, + system_instruction, transaction::Transaction, +}; +use token_program::state::mint::Mint; + +pub async fn initialize( + context: &mut ProgramTestContext, + mint_authority: Pubkey, + freeze_authority: Option, + program_id: &Pubkey, +) -> Result { + // Mint account keypair. + let account = Keypair::new(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_mint( + &spl_token::ID, + &account.pubkey(), + &mint_authority, + freeze_authority.as_ref(), + 0, + ) + .unwrap(); + // Switches the program id in case we are using a "custom" one. + initialize_ix.program_id = *program_id; + + // Create a new account and initialize as a mint. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size), + account_size as u64, + program_id, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + Ok(account.pubkey()) +} + +pub async fn mint( + context: &mut ProgramTestContext, + mint: &Pubkey, + account: &Pubkey, + mint_authority: &Keypair, + amount: u64, + program_id: &Pubkey, +) -> Result<(), BanksClientError> { + let mut mint_ix = spl_token::instruction::mint_to( + &spl_token::ID, + mint, + account, + &mint_authority.pubkey(), + &[], + amount, + ) + .unwrap(); + // Switches the program id to the token program. + mint_ix.program_id = *program_id; + + let tx = Transaction::new_signed_with_payer( + &[mint_ix], + Some(&context.payer.pubkey()), + &[&context.payer, mint_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await +} diff --git a/p-token/tests/setup/mod.rs b/p-token/tests/setup/mod.rs new file mode 100644 index 0000000..4ef329a --- /dev/null +++ b/p-token/tests/setup/mod.rs @@ -0,0 +1,4 @@ +#[allow(dead_code)] +pub mod account; +#[allow(dead_code)] +pub mod mint; diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs new file mode 100644 index 0000000..287e804 --- /dev/null +++ b/p-token/tests/transfer.rs @@ -0,0 +1,94 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] +#[tokio::test] +async fn transfer(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account with 100 tokens. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program) + .await + .unwrap(); + + mint::mint( + &mut context, + &mint, + &account, + &mint_authority, + 100, + &token_program, + ) + .await + .unwrap(); + + // When we transfer the tokens. + + let destination = Pubkey::new_unique(); + + let destination_account = + account::initialize(&mut context, &mint, &destination, &token_program) + .await + .unwrap(); + + let mut transfer_ix = spl_token::instruction::transfer( + &spl_token::ID, + &account, + &destination_account, + &owner.pubkey(), + &[], + 100, + ) + .unwrap(); + transfer_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[transfer_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.amount == 0); +} From 38927db2dd0c011c1f5bbe69f067e45784311d04 Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 3 Oct 2024 23:25:20 +0100 Subject: [PATCH 265/335] Use published crate --- p-token/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 8bd475e..82f78fe 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -18,7 +18,7 @@ test-sbf = [] [dependencies] bytemuck = { version="1.18.0", features=["derive"] } -pinocchio = { version="0.2", path="/Users/febo/Developer/febo/pinocchio/sdk/pinocchio" } +pinocchio = "0.2" pinocchio-pubkey = "0.1" [dev-dependencies] From 2adf089ef09176e8af08843a14b4a82c900847fa Mon Sep 17 00:00:00 2001 From: febo Date: Sun, 27 Oct 2024 01:19:11 +0100 Subject: [PATCH 266/335] Add interface crate --- interface/Cargo.toml | 12 + {p-token => interface}/src/error.rs | 0 interface/src/instruction.rs | 518 ++++++++++++++++++ interface/src/lib.rs | 4 + {p-token => interface}/src/native_mint.rs | 3 +- {p-token => interface}/src/state/account.rs | 0 {p-token => interface}/src/state/mint.rs | 0 {p-token => interface}/src/state/mod.rs | 19 +- .../src/state/multisignature.rs | 0 p-token/Cargo.toml | 5 +- p-token/src/entrypoint.rs | 4 +- p-token/src/lib.rs | 3 - p-token/src/processor/initialize_account.rs | 74 +-- p-token/src/processor/initialize_mint.rs | 34 +- p-token/src/processor/mint_to.rs | 16 +- p-token/src/processor/mod.rs | 10 +- p-token/src/processor/transfer.rs | 16 +- p-token/tests/initialize_mint.rs | 2 +- p-token/tests/setup/mint.rs | 2 +- 19 files changed, 623 insertions(+), 99 deletions(-) create mode 100644 interface/Cargo.toml rename {p-token => interface}/src/error.rs (100%) create mode 100644 interface/src/instruction.rs create mode 100644 interface/src/lib.rs rename {p-token => interface}/src/native_mint.rs (71%) rename {p-token => interface}/src/state/account.rs (100%) rename {p-token => interface}/src/state/mint.rs (100%) rename {p-token => interface}/src/state/mod.rs (86%) rename {p-token => interface}/src/state/multisignature.rs (100%) diff --git a/interface/Cargo.toml b/interface/Cargo.toml new file mode 100644 index 0000000..2155388 --- /dev/null +++ b/interface/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "token-interface" +version = "0.0.0" +edition = "2021" +readme = "./README.md" +license-file = "../LICENSE" +publish = false + +[dependencies] +bytemuck = { version="1.18.0", features=["derive"] } +pinocchio = "0.6" +pinocchio-pubkey = "0.2" diff --git a/p-token/src/error.rs b/interface/src/error.rs similarity index 100% rename from p-token/src/error.rs rename to interface/src/error.rs diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs new file mode 100644 index 0000000..08f7cc9 --- /dev/null +++ b/interface/src/instruction.rs @@ -0,0 +1,518 @@ +//! Instruction types + +use pinocchio::{program_error::ProgramError, pubkey::Pubkey}; + +use crate::{error::TokenError, state::PodCOption}; + +/// Instructions supported by the token program. +#[repr(C)] +#[derive(Clone, Debug, PartialEq)] +pub enum TokenInstruction<'a> { + /// Initializes a new mint and optionally deposits all the newly minted + /// tokens in an account. + /// + /// The `InitializeMint` instruction requires no signers and MUST be + /// included within the same Transaction as the system program's + /// `CreateAccount` instruction that creates the account being initialized. + /// Otherwise another party can acquire ownership of the uninitialized + /// account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The mint to initialize. + /// 1. `[]` Rent sysvar + InitializeMint { + /// Number of base 10 digits to the right of the decimal place. + decimals: u8, + /// The authority/multisignature to mint tokens. + mint_authority: Pubkey, + /// The freeze authority/multisignature of the mint. + freeze_authority: PodCOption, + }, + + /// Initializes a new account to hold tokens. If this account is associated + /// with the native mint then the token balance of the initialized account + /// will be equal to the amount of SOL in the account. If this account is + /// associated with another mint, that mint must be initialized before this + /// command can succeed. + /// + /// The `InitializeAccount` instruction requires no signers and MUST be + /// included within the same Transaction as the system program's + /// `CreateAccount` instruction that creates the account being initialized. + /// Otherwise another party can acquire ownership of the uninitialized + /// account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// 1. `[]` The mint this account will be associated with. + /// 2. `[]` The new account's owner/multisignature. + /// 3. `[]` Rent sysvar + InitializeAccount, + + /// Initializes a multisignature account with N provided signers. + /// + /// Multisignature accounts can used in place of any single owner/delegate + /// accounts in any token instruction that require an owner/delegate to be + /// present. The variant field represents the number of signers (M) + /// required to validate this multisignature account. + /// + /// The `InitializeMultisig` instruction requires no signers and MUST be + /// included within the same Transaction as the system program's + /// `CreateAccount` instruction that creates the account being initialized. + /// Otherwise another party can acquire ownership of the uninitialized + /// account. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The multisignature account to initialize. + /// 1. `[]` Rent sysvar + /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= + /// 11. + InitializeMultisig { + /// The number of signers (M) required to validate this multisignature + /// account. + m: u8, + }, + + /// Transfers tokens from one account to another either directly or via a + /// delegate. If this account is associated with the native mint then equal + /// amounts of SOL and Tokens will be transferred to the destination + /// account. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The source account. + /// 1. `[writable]` The destination account. + /// 2. `[signer]` The source account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The source account. + /// 1. `[writable]` The destination account. + /// 2. `[]` The source account's multisignature owner/delegate. + /// 3. ..3+M `[signer]` M signer accounts. + Transfer { + /// The amount of tokens to transfer. + amount: u64, + }, + + /// Approves a delegate. A delegate is given the authority over tokens on + /// behalf of the source account's owner. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The source account. + /// 1. `[]` The delegate. + /// 2. `[signer]` The source account owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The source account. + /// 1. `[]` The delegate. + /// 2. `[]` The source account's multisignature owner. + /// 3. ..3+M `[signer]` M signer accounts + Approve { + /// The amount of tokens the delegate is approved for. + amount: u64, + }, + + /// Revokes the delegate's authority. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The source account. + /// 1. `[signer]` The source account owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The source account. + /// 1. `[]` The source account's multisignature owner. + /// 2. ..2+M `[signer]` M signer accounts + Revoke, + + /// Sets a new authority of a mint or account. + /// + /// Accounts expected by this instruction: + /// + /// * Single authority + /// 0. `[writable]` The mint or account to change the authority of. + /// 1. `[signer]` The current authority of the mint or account. + /// + /// * Multisignature authority + /// 0. `[writable]` The mint or account to change the authority of. + /// 1. `[]` The mint's or account's current multisignature authority. + /// 2. ..2+M `[signer]` M signer accounts + SetAuthority { + /// The type of authority to update. + authority_type: AuthorityType, + /// The new authority + new_authority: PodCOption, + }, + + /// Mints new tokens to an account. The native mint does not support + /// minting. + /// + /// Accounts expected by this instruction: + /// + /// * Single authority + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[signer]` The mint's minting authority. + /// + /// * Multisignature authority + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[]` The mint's multisignature mint-tokens authority. + /// 3. ..3+M `[signer]` M signer accounts. + MintTo { + /// The amount of new tokens to mint. + amount: u64, + }, + + /// Burns tokens by removing them from an account. `Burn` does not support + /// accounts associated with the native mint, use `CloseAccount` instead. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. `[writable]` The token mint. + /// 2. `[signer]` The account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. `[writable]` The token mint. + /// 2. `[]` The account's multisignature owner/delegate. + /// 3. ..3+M `[signer]` M signer accounts. + Burn { + /// The amount of tokens to burn. + amount: u64, + }, + + /// Close an account by transferring all its SOL to the destination account. + /// Non-native accounts may only be closed if its token amount is zero. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The account to close. + /// 1. `[writable]` The destination account. + /// 2. `[signer]` The account's owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The account to close. + /// 1. `[writable]` The destination account. + /// 2. `[]` The account's multisignature owner. + /// 3. ..3+M `[signer]` M signer accounts. + CloseAccount, + + /// Freeze an Initialized account using the Mint's freeze_authority (if + /// set). + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The account to freeze. + /// 1. `[]` The token mint. + /// 2. `[signer]` The mint freeze authority. + /// + /// * Multisignature owner + /// 0. `[writable]` The account to freeze. + /// 1. `[]` The token mint. + /// 2. `[]` The mint's multisignature freeze authority. + /// 3. ..3+M `[signer]` M signer accounts. + FreezeAccount, + + /// Thaw a Frozen account using the Mint's freeze_authority (if set). + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The account to freeze. + /// 1. `[]` The token mint. + /// 2. `[signer]` The mint freeze authority. + /// + /// * Multisignature owner + /// 0. `[writable]` The account to freeze. + /// 1. `[]` The token mint. + /// 2. `[]` The mint's multisignature freeze authority. + /// 3. ..3+M `[signer]` M signer accounts. + ThawAccount, + + /// Transfers tokens from one account to another either directly or via a + /// delegate. If this account is associated with the native mint then equal + /// amounts of SOL and Tokens will be transferred to the destination + /// account. + /// + /// This instruction differs from Transfer in that the token mint and + /// decimals value is checked by the caller. This may be useful when + /// creating transactions offline or within a hardware wallet. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The source account. + /// 1. `[]` The token mint. + /// 2. `[writable]` The destination account. + /// 3. `[signer]` The source account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The source account. + /// 1. `[]` The token mint. + /// 2. `[writable]` The destination account. + /// 3. `[]` The source account's multisignature owner/delegate. + /// 4. ..4+M `[signer]` M signer accounts. + TransferChecked { + /// The amount of tokens to transfer. + amount: u64, + /// Expected number of base 10 digits to the right of the decimal place. + decimals: u8, + }, + + /// Approves a delegate. A delegate is given the authority over tokens on + /// behalf of the source account's owner. + /// + /// This instruction differs from Approve in that the token mint and + /// decimals value is checked by the caller. This may be useful when + /// creating transactions offline or within a hardware wallet. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner + /// 0. `[writable]` The source account. + /// 1. `[]` The token mint. + /// 2. `[]` The delegate. + /// 3. `[signer]` The source account owner. + /// + /// * Multisignature owner + /// 0. `[writable]` The source account. + /// 1. `[]` The token mint. + /// 2. `[]` The delegate. + /// 3. `[]` The source account's multisignature owner. + /// 4. ..4+M `[signer]` M signer accounts + ApproveChecked { + /// The amount of tokens the delegate is approved for. + amount: u64, + /// Expected number of base 10 digits to the right of the decimal place. + decimals: u8, + }, + + /// Mints new tokens to an account. The native mint does not support + /// minting. + /// + /// This instruction differs from MintTo in that the decimals value is + /// checked by the caller. This may be useful when creating transactions + /// offline or within a hardware wallet. + /// + /// Accounts expected by this instruction: + /// + /// * Single authority + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[signer]` The mint's minting authority. + /// + /// * Multisignature authority + /// 0. `[writable]` The mint. + /// 1. `[writable]` The account to mint tokens to. + /// 2. `[]` The mint's multisignature mint-tokens authority. + /// 3. ..3+M `[signer]` M signer accounts. + MintToChecked { + /// The amount of new tokens to mint. + amount: u64, + /// Expected number of base 10 digits to the right of the decimal place. + decimals: u8, + }, + + /// Burns tokens by removing them from an account. `BurnChecked` does not + /// support accounts associated with the native mint, use `CloseAccount` + /// instead. + /// + /// This instruction differs from Burn in that the decimals value is checked + /// by the caller. This may be useful when creating transactions offline or + /// within a hardware wallet. + /// + /// Accounts expected by this instruction: + /// + /// * Single owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. `[writable]` The token mint. + /// 2. `[signer]` The account's owner/delegate. + /// + /// * Multisignature owner/delegate + /// 0. `[writable]` The account to burn from. + /// 1. `[writable]` The token mint. + /// 2. `[]` The account's multisignature owner/delegate. + /// 3. ..3+M `[signer]` M signer accounts. + BurnChecked { + /// The amount of tokens to burn. + amount: u64, + /// Expected number of base 10 digits to the right of the decimal place. + decimals: u8, + }, + + /// Like InitializeAccount, but the owner pubkey is passed via instruction + /// data rather than the accounts list. This variant may be preferable + /// when using Cross Program Invocation from an instruction that does + /// not need the owner's `AccountInfo` otherwise. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// 1. `[]` The mint this account will be associated with. + /// 3. `[]` Rent sysvar + InitializeAccount2 { + /// The new account's owner/multisignature. + owner: Pubkey, + }, + + /// Given a wrapped / native token account (a token account containing SOL) + /// updates its amount field based on the account's underlying `lamports`. + /// This is useful if a non-wrapped SOL account uses + /// `system_instruction::transfer` to move lamports to a wrapped token + /// account, and needs to have its token `amount` field updated. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The native token account to sync with its underlying + /// lamports. + SyncNative, + + /// Like InitializeAccount2, but does not require the Rent sysvar to be + /// provided + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// 1. `[]` The mint this account will be associated with. + InitializeAccount3 { + /// The new account's owner/multisignature. + owner: Pubkey, + }, + + /// Like InitializeMultisig, but does not require the Rent sysvar to be + /// provided + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The multisignature account to initialize. + /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= + /// 11. + InitializeMultisig2 { + /// The number of signers (M) required to validate this multisignature + /// account. + m: u8, + }, + + /// Like [`InitializeMint`], but does not require the Rent sysvar to be + /// provided + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The mint to initialize. + InitializeMint2 { + /// Number of base 10 digits to the right of the decimal place. + decimals: u8, + /// The authority/multisignature to mint tokens. + mint_authority: Pubkey, + /// The freeze authority/multisignature of the mint. + freeze_authority: PodCOption, + }, + + /// Gets the required size of an account for the given mint as a + /// little-endian `u64`. + /// + /// Return data can be fetched using `sol_get_return_data` and deserializing + /// the return data as a little-endian `u64`. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[]` The mint to calculate for + GetAccountDataSize, // typically, there's also data, but this program ignores it + + /// Initialize the Immutable Owner extension for the given token account + /// + /// Fails if the account has already been initialized, so must be called + /// before `InitializeAccount`. + /// + /// No-ops in this version of the program, but is included for compatibility + /// with the Associated Token Account program. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` The account to initialize. + /// + /// Data expected by this instruction: + /// None + InitializeImmutableOwner, + + /// Convert an Amount of tokens to a UiAmount `string`, using the given + /// mint. In this version of the program, the mint can only specify the + /// number of decimals. + /// + /// Fails on an invalid mint. + /// + /// Return data can be fetched using `sol_get_return_data` and deserialized + /// with `String::from_utf8`. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[]` The mint to calculate for + AmountToUiAmount { + /// The amount of tokens to reformat. + amount: u64, + }, + + /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using + /// the given mint. In this version of the program, the mint can only + /// specify the number of decimals. + /// + /// Return data can be fetched using `sol_get_return_data` and deserializing + /// the return data as a little-endian `u64`. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[]` The mint to calculate for + UiAmountToAmount { + /// The ui_amount of tokens to reformat. + ui_amount: &'a str, + }, + // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the + // latter remains a superset of this instruction set. New variants also need to be added to + // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility +} + +/// Specifies the authority type for SetAuthority instructions +#[repr(u8)] +#[derive(Clone, Debug, PartialEq)] +pub enum AuthorityType { + /// Authority to mint new tokens + MintTokens, + /// Authority to freeze any account associated with the Mint + FreezeAccount, + /// Owner of a given token account + AccountOwner, + /// Authority to close a token account + CloseAccount, +} + +impl AuthorityType { + fn into(&self) -> u8 { + match self { + AuthorityType::MintTokens => 0, + AuthorityType::FreezeAccount => 1, + AuthorityType::AccountOwner => 2, + AuthorityType::CloseAccount => 3, + } + } + + fn from(index: u8) -> Result { + match index { + 0 => Ok(AuthorityType::MintTokens), + 1 => Ok(AuthorityType::FreezeAccount), + 2 => Ok(AuthorityType::AccountOwner), + 3 => Ok(AuthorityType::CloseAccount), + _ => Err(TokenError::InvalidInstruction.into()), + } + } +} diff --git a/interface/src/lib.rs b/interface/src/lib.rs new file mode 100644 index 0000000..8c4d430 --- /dev/null +++ b/interface/src/lib.rs @@ -0,0 +1,4 @@ +pub mod error; +pub mod instruction; +pub mod native_mint; +pub mod state; diff --git a/p-token/src/native_mint.rs b/interface/src/native_mint.rs similarity index 71% rename from p-token/src/native_mint.rs rename to interface/src/native_mint.rs index eb8073e..a99a5bc 100644 --- a/p-token/src/native_mint.rs +++ b/interface/src/native_mint.rs @@ -6,8 +6,7 @@ use pinocchio::pubkey::Pubkey; pub const DECIMALS: u8 = 9; // The Mint for native SOL Token accounts -pub const ID: Pubkey = - pinocchio_pubkey::declare_pubkey!("So11111111111111111111111111111111111111112"); +pub const ID: Pubkey = pinocchio_pubkey::pubkey!("So11111111111111111111111111111111111111112"); #[inline(always)] pub fn is_native_mint(mint: &Pubkey) -> bool { diff --git a/p-token/src/state/account.rs b/interface/src/state/account.rs similarity index 100% rename from p-token/src/state/account.rs rename to interface/src/state/account.rs diff --git a/p-token/src/state/mint.rs b/interface/src/state/mint.rs similarity index 100% rename from p-token/src/state/mint.rs rename to interface/src/state/mint.rs diff --git a/p-token/src/state/mod.rs b/interface/src/state/mod.rs similarity index 86% rename from p-token/src/state/mod.rs rename to interface/src/state/mod.rs index 3f48173..95b2a6a 100644 --- a/p-token/src/state/mod.rs +++ b/interface/src/state/mod.rs @@ -36,10 +36,14 @@ impl From> for PodCOption { } impl PodCOption { + pub const NONE: [u8; 4] = [0, 0, 0, 0]; + + pub const SOME: [u8; 4] = [1, 0, 0, 0]; + /// Returns `true` if the option is a `None` value. #[inline] pub fn is_none(&self) -> bool { - self.tag == [0, 0, 0, 0] + self.tag == Self::NONE } /// Returns `true` if the option is a `Some` value. @@ -77,6 +81,19 @@ impl PodCOption { Some(&mut self.value) } } + + #[inline] + pub fn set(&mut self, value: T) { + self.tag = Self::SOME; + self.value = value; + } + + #[inline] + pub fn clear(&mut self) { + self.tag = Self::NONE; + // we don't need to zero the value since the tag + // indicates it is a `None` value + } } /// ## Safety diff --git a/p-token/src/state/multisignature.rs b/interface/src/state/multisignature.rs similarity index 100% rename from p-token/src/state/multisignature.rs rename to interface/src/state/multisignature.rs diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 82f78fe..57a8837 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -18,8 +18,9 @@ test-sbf = [] [dependencies] bytemuck = { version="1.18.0", features=["derive"] } -pinocchio = "0.2" -pinocchio-pubkey = "0.1" +pinocchio = "0.6" +pinocchio-pubkey = "0.2" +token-interface = { version = "^0", path = "../interface" } [dev-dependencies] assert_matches = "1.5.0" diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index a569c7a..6683771 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -1,6 +1,6 @@ use pinocchio::{ - account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, + account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey, + ProgramResult, }; use crate::processor::{ diff --git a/p-token/src/lib.rs b/p-token/src/lib.rs index 7c28f42..f397909 100644 --- a/p-token/src/lib.rs +++ b/p-token/src/lib.rs @@ -1,9 +1,6 @@ //! A lighter Token program for SVM. mod entrypoint; -pub mod error; -pub mod native_mint; mod processor; -pub mod state; pinocchio_pubkey::declare_id!("TokenLight111111111111111111111111111111111"); diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs index 7edfa2f..222d486 100644 --- a/p-token/src/processor/initialize_account.rs +++ b/p-token/src/processor/initialize_account.rs @@ -1,16 +1,12 @@ -use std::mem::size_of; - -use bytemuck::{Pod, Zeroable}; use pinocchio::{ account_info::AccountInfo, - entrypoint::ProgramResult, - get_account_info, program_error::ProgramError, - pubkey::{self, Pubkey}, + pubkey::Pubkey, sysvars::{rent::Rent, Sysvar}, + ProgramResult, }; - -use crate::{ +use std::mem::size_of; +use token_interface::{ error::TokenError, native_mint::is_native_mint, state::{ @@ -25,36 +21,30 @@ use super::check_account_owner; pub fn process_initialize_account( program_id: &Pubkey, accounts: &[AccountInfo], - args: Option<&InitializeAccount>, + owner: Option<&Pubkey>, _rent_sysvar_account: bool, ) -> ProgramResult { - let [new_account_info, mint_info, _remaning @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - - let owner = if let Some(InitializeAccount { owner }) = args { - owner + let (new_account_info, mint_info, owner) = if let Some(owner) = owner { + let [new_account_info, mint_info, _remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (new_account_info, mint_info, owner) } else { - get_account_info!(accounts, 2).key() + let [new_account_info, mint_info, owner_info, _remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (new_account_info, mint_info, owner_info.key()) }; - // FEBO: ~408 CU can be saved by removing the rent check (is_exempt seems to - // be very expensive). - // - // The transaction will naturally fail if the account is not rent exempt with - // a TransactionError::InsufficientFundsForRent error. - /* + /* TODO: Implement rent exemption let rent = Rent::get()?; - if !rent.is_exempt( - unsafe { *new_account_info.unchecked_borrow_lamports() }, - size_of::(), - ) { - return Err(Token::NotRentExempt); + if !rent.is_exempt_scaled(new_account_info.lamports(), size_of::()) { + return Err(TokenError::NotRentExempt.into()); } */ - let account_data = unsafe { new_account_info.unchecked_borrow_mut_data() }; + let account_data = unsafe { new_account_info.borrow_mut_data_unchecked() }; let account = bytemuck::try_from_bytes_mut::(account_data) .map_err(|_error| ProgramError::InvalidAccountData)?; @@ -67,19 +57,19 @@ pub fn process_initialize_account( if !is_native_mint { check_account_owner(program_id, mint_info)?; - let mint_data = unsafe { mint_info.unchecked_borrow_data() }; - let mint = bytemuck::from_bytes::(mint_data); + let mint_data = unsafe { mint_info.borrow_data_unchecked() }; + let mint = bytemuck::try_from_bytes::(mint_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; - let initialized: bool = mint.is_initialized.into(); - if !initialized { + if !bool::from(mint.is_initialized) { return Err(TokenError::InvalidMint.into()); } } - pubkey::copy(&mut account.mint, mint_info.key()); - pubkey::copy(&mut account.owner, owner); - account.close_authority = PodCOption::from(None); - account.delegate = PodCOption::from(None); + account.mint = *mint_info.key(); + account.owner = *owner; + account.close_authority.clear(); + account.delegate.clear(); account.delegated_amount = 0u64.to_le_bytes(); account.state = AccountState::Initialized as u8; @@ -90,23 +80,15 @@ pub fn process_initialize_account( account.is_native = PodCOption::from(Some(rent_exempt_reserve.to_le_bytes())); unsafe { account.amount = new_account_info - .unchecked_borrow_lamports() + .borrow_lamports_unchecked() .checked_sub(rent_exempt_reserve) .ok_or(TokenError::Overflow)? .to_le_bytes() } } else { - account.is_native = PodCOption::from(None); + account.is_native.clear(); account.amount = 0u64.to_le_bytes(); }; Ok(()) } - -/// Instruction data for the `InitializeAccount` instruction. -#[repr(C)] -#[derive(Clone, Copy, Default, Pod, Zeroable)] -pub struct InitializeAccount { - /// The new account's owner/multisignature. - pub owner: Pubkey, -} diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 36c7f64..15b1545 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -1,14 +1,12 @@ -use std::mem::size_of; - use bytemuck::{Pod, Zeroable}; use pinocchio::{ account_info::AccountInfo, - entrypoint::ProgramResult, program_error::ProgramError, pubkey::{Pubkey, PUBKEY_BYTES}, + ProgramResult, }; - -use crate::{ +use std::mem::size_of; +use token_interface::{ error::TokenError, state::{mint::Mint, PodCOption}, }; @@ -18,33 +16,32 @@ pub fn process_initialize_mint( args: &InitializeMint, _rent_sysvar_account: bool, ) -> ProgramResult { + // Validate the mint account. + let [mint_info, _remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - let mint_data = &mut mint_info.try_borrow_mut_data()?; - let mint = bytemuck::from_bytes_mut::(mint_data); + let mint_data = unsafe { mint_info.borrow_mut_data_unchecked() }; + let mint = bytemuck::try_from_bytes_mut::(mint_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; if mint.is_initialized.into() { return Err(TokenError::AlreadyInUse.into()); } - // FEBO: ~408 CU can be saved by removing the rent check (is_exempt seems to - // be very expensive). - // - // The transaction will naturally fail if the account is not rent exempt with - // a TransactionError::InsufficientFundsForRent error. - /* + // Check rent-exempt status of the mint account. + + /* TODO: Implement rent exemption let rent = Rent::get()?; - if !rent.is_exempt( - unsafe { *mint_info.unchecked_borrow_lamports() }, - size_of::(), - ) { - return Err(TokenError::NotRentExempt); + if !rent.is_exempt_scaled(mint_info.lamports(), size_of::()) { + return Err(TokenError::NotRentExempt.into()); } */ + // Initialize the mint. + mint.mint_authority = PodCOption::from(Some(args.data.mint_authority)); mint.decimals = args.data.decimals; mint.is_initialized = true.into(); @@ -90,6 +87,7 @@ impl<'a> InitializeMint<'a> { } } +/// Base information for the mint. #[repr(C)] #[derive(Clone, Copy, Default, Pod, Zeroable)] pub struct MintData { diff --git a/p-token/src/processor/mint_to.rs b/p-token/src/processor/mint_to.rs index 4ce72cc..1ce35f3 100644 --- a/p-token/src/processor/mint_to.rs +++ b/p-token/src/processor/mint_to.rs @@ -1,9 +1,7 @@ use pinocchio::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; - -use crate::{ +use token_interface::{ error::TokenError, native_mint::is_native_mint, state::{account::Account, mint::Mint}, @@ -23,8 +21,9 @@ pub fn process_mint_to( // destination account - let account_data = unsafe { destination_account_info.unchecked_borrow_mut_data() }; - let destination_account = bytemuck::from_bytes_mut::(account_data); + let account_data = unsafe { destination_account_info.borrow_mut_data_unchecked() }; + let destination_account = bytemuck::try_from_bytes_mut::(account_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; if destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -38,8 +37,9 @@ pub fn process_mint_to( return Err(TokenError::MintMismatch.into()); } - let mint_data = unsafe { mint_info.unchecked_borrow_mut_data() }; - let mint = bytemuck::from_bytes_mut::(mint_data); + let mint_data = unsafe { mint_info.borrow_mut_data_unchecked() }; + let mint = bytemuck::try_from_bytes_mut::(mint_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; if let Some(expected_decimals) = expected_decimals { if expected_decimals != mint.decimals { diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 98cd433..d741cb9 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -1,11 +1,7 @@ use pinocchio::{ - account_info::AccountInfo, - entrypoint::ProgramResult, - program_error::ProgramError, - pubkey::{self, Pubkey}, + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; - -use crate::{ +use token_interface::{ error::TokenError, state::multisignature::{Multisig, MAX_SIGNERS}, }; @@ -46,7 +42,7 @@ pub fn validate_owner( for signer in signers.iter() { for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() { - if pubkey::compare(key, signer.key()) && !matched[position] { + if key == signer.key() && !matched[position] { if !signer.is_signer() { return Err(ProgramError::MissingRequiredSignature); } diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs index 7fe88ca..819cc3a 100644 --- a/p-token/src/processor/transfer.rs +++ b/p-token/src/processor/transfer.rs @@ -1,9 +1,7 @@ use pinocchio::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; - -use crate::{ +use token_interface::{ error::TokenError, native_mint::is_native_mint, state::{account::Account, mint::Mint, PodCOption}, @@ -56,11 +54,13 @@ pub fn process_transfer( // Validates source and destination accounts. - let source_account_data = unsafe { source_account_info.unchecked_borrow_mut_data() }; - let source_account = bytemuck::from_bytes_mut::(source_account_data); + let source_account_data = unsafe { source_account_info.borrow_mut_data_unchecked() }; + let source_account = bytemuck::try_from_bytes_mut::(source_account_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; - let destination_account_data = unsafe { destination_account_info.unchecked_borrow_mut_data() }; - let destination_account = bytemuck::from_bytes_mut::(destination_account_data); + let destination_account_data = unsafe { destination_account_info.borrow_mut_data_unchecked() }; + let destination_account = bytemuck::try_from_bytes_mut::(destination_account_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; if source_account.is_frozen() || destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 10194d3..547b53e 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -11,7 +11,7 @@ use solana_sdk::{ system_instruction, transaction::Transaction, }; -use token_program::state::mint::Mint; +use token_interface::state::mint::Mint; #[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] diff --git a/p-token/tests/setup/mint.rs b/p-token/tests/setup/mint.rs index d428c68..146aae4 100644 --- a/p-token/tests/setup/mint.rs +++ b/p-token/tests/setup/mint.rs @@ -5,7 +5,7 @@ use solana_sdk::{ program_error::ProgramError, pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, transaction::Transaction, }; -use token_program::state::mint::Mint; +use token_interface::state::mint::Mint; pub async fn initialize( context: &mut ProgramTestContext, From 82240a1cb9f224bd8d56112f6845e485c51148ac Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 12 Nov 2024 02:06:10 +0000 Subject: [PATCH 267/335] Fix clippy warning --- interface/src/instruction.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index 08f7cc9..de69609 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -497,7 +497,7 @@ pub enum AuthorityType { } impl AuthorityType { - fn into(&self) -> u8 { + pub fn into(&self) -> u8 { match self { AuthorityType::MintTokens => 0, AuthorityType::FreezeAccount => 1, @@ -506,7 +506,7 @@ impl AuthorityType { } } - fn from(index: u8) -> Result { + pub fn from(index: u8) -> Result { match index { 0 => Ok(AuthorityType::MintTokens), 1 => Ok(AuthorityType::FreezeAccount), From 80883acabf6d31a0dee23d6829fc412669ee2b4c Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 12 Nov 2024 10:15:51 +0000 Subject: [PATCH 268/335] Add pod types --- interface/Cargo.toml | 11 ++++++----- interface/src/state/account.rs | 12 ++++++++---- interface/src/state/mint.rs | 4 ++-- interface/src/state/mod.rs | 20 ++++++++++++++++++++ p-token/src/lib.rs | 2 +- p-token/src/processor/initialize_account.rs | 8 ++++---- p-token/src/processor/mint_to.rs | 8 ++++---- p-token/src/processor/transfer.rs | 12 ++++++------ 8 files changed, 51 insertions(+), 26 deletions(-) diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 2155388..628cb2a 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "token-interface" version = "0.0.0" -edition = "2021" +edition = { workspace = true } readme = "./README.md" -license-file = "../LICENSE" +license = { workspace = true } +repository = { workspace = true } publish = false [dependencies] -bytemuck = { version="1.18.0", features=["derive"] } -pinocchio = "0.6" -pinocchio-pubkey = "0.2" +bytemuck = { workspace = true } +pinocchio = { workspace = true } +pinocchio-pubkey = { workspace = true } diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index 8b80209..73deac4 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -1,7 +1,7 @@ use bytemuck::{Pod, Zeroable}; use pinocchio::pubkey::Pubkey; -use super::PodCOption; +use super::{PodCOption, PodU64}; /// Account data. #[repr(C)] @@ -14,7 +14,7 @@ pub struct Account { pub owner: Pubkey, /// The amount of tokens this account holds. - pub amount: [u8; 8], + pub amount: PodU64, /// If `delegate` is `Some` then `delegated_amount` represents /// the amount authorized by the delegate @@ -27,10 +27,10 @@ pub struct Account { /// rent-exempt reserve. An Account is required to be rent-exempt, so /// the value is used by the Processor to ensure that wrapped SOL /// accounts do not drop below this threshold. - pub is_native: PodCOption<[u8; 8]>, + pub is_native: PodCOption, /// The amount delegated - pub delegated_amount: [u8; 8], + pub delegated_amount: PodU64, /// Optional authority to close the account. pub close_authority: PodCOption, @@ -46,6 +46,10 @@ impl Account { pub fn is_frozen(&self) -> bool { self.state == AccountState::Frozen as u8 } + + pub fn amount(&self) -> u64 { + self.amount.into() + } } /// Account state. diff --git a/interface/src/state/mint.rs b/interface/src/state/mint.rs index 84e9c8e..2d42391 100644 --- a/interface/src/state/mint.rs +++ b/interface/src/state/mint.rs @@ -1,7 +1,7 @@ use bytemuck::{Pod, Zeroable}; use pinocchio::pubkey::Pubkey; -use super::{PodBool, PodCOption}; +use super::{PodBool, PodCOption, PodU64}; /// Mint data. #[repr(C)] @@ -14,7 +14,7 @@ pub struct Mint { pub mint_authority: PodCOption, /// Total supply of tokens. - pub supply: [u8; 8], + pub supply: PodU64, /// Number of base 10 digits to the right of the decimal place. pub decimals: u8, diff --git a/interface/src/state/mod.rs b/interface/src/state/mod.rs index 95b2a6a..c26918b 100644 --- a/interface/src/state/mod.rs +++ b/interface/src/state/mod.rs @@ -133,3 +133,23 @@ impl From for bool { b.0 != 0 } } + +#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] +#[repr(C)] +pub struct PodU64(pub [u8; 8]); + +impl PodU64 { + pub const fn from_primitive(n: u64) -> Self { + Self(n.to_le_bytes()) + } +} +impl From for PodU64 { + fn from(n: u64) -> Self { + Self::from_primitive(n) + } +} +impl From for u64 { + fn from(pod: PodU64) -> Self { + Self::from_le_bytes(pod.0) + } +} diff --git a/p-token/src/lib.rs b/p-token/src/lib.rs index f397909..44dcf52 100644 --- a/p-token/src/lib.rs +++ b/p-token/src/lib.rs @@ -3,4 +3,4 @@ mod entrypoint; mod processor; -pinocchio_pubkey::declare_id!("TokenLight111111111111111111111111111111111"); +pinocchio_pubkey::declare_id!("Tokenocchio11111111111111111111111111111111"); diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs index 222d486..f53a8c4 100644 --- a/p-token/src/processor/initialize_account.rs +++ b/p-token/src/processor/initialize_account.rs @@ -70,24 +70,24 @@ pub fn process_initialize_account( account.owner = *owner; account.close_authority.clear(); account.delegate.clear(); - account.delegated_amount = 0u64.to_le_bytes(); + account.delegated_amount = 0u64.into(); account.state = AccountState::Initialized as u8; if is_native_mint { let rent = Rent::get()?; let rent_exempt_reserve = rent.minimum_balance(size_of::()); - account.is_native = PodCOption::from(Some(rent_exempt_reserve.to_le_bytes())); + account.is_native = PodCOption::from(Some(rent_exempt_reserve.into())); unsafe { account.amount = new_account_info .borrow_lamports_unchecked() .checked_sub(rent_exempt_reserve) .ok_or(TokenError::Overflow)? - .to_le_bytes() + .into() } } else { account.is_native.clear(); - account.amount = 0u64.to_le_bytes(); + account.amount = 0u64.into(); }; Ok(()) diff --git a/p-token/src/processor/mint_to.rs b/p-token/src/processor/mint_to.rs index 1ce35f3..acecc7a 100644 --- a/p-token/src/processor/mint_to.rs +++ b/p-token/src/processor/mint_to.rs @@ -57,15 +57,15 @@ pub fn process_mint_to( check_account_owner(program_id, destination_account_info)?; } - let destination_amount = u64::from_le_bytes(destination_account.amount) + let destination_amount = u64::from(destination_account.amount) .checked_add(amount) .ok_or(ProgramError::InvalidAccountData)?; - destination_account.amount = destination_amount.to_le_bytes(); + destination_account.amount = destination_amount.into(); - let mint_supply = u64::from_le_bytes(mint.supply) + let mint_supply = u64::from(mint.supply) .checked_add(amount) .ok_or(ProgramError::InvalidAccountData)?; - mint.supply = mint_supply.to_le_bytes(); + mint.supply = mint_supply.into(); Ok(()) } diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs index 819cc3a..e4a6702 100644 --- a/p-token/src/processor/transfer.rs +++ b/p-token/src/processor/transfer.rs @@ -69,7 +69,7 @@ pub fn process_transfer( // FEBO: Implicitly validates that the account has enough tokens by calculating the // remaining amount. The amount is only updated on the account if the transfer // is successful. - let remaining_amount = u64::from_le_bytes(source_account.amount) + let remaining_amount = u64::from(source_account.amount) .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; @@ -99,12 +99,12 @@ pub fn process_transfer( if source_account.delegate.as_ref() == Some(authority_info.key()) { validate_owner(program_id, authority_info.key(), authority_info, remaning)?; - let delegated_amount = u64::from_le_bytes(source_account.delegated_amount) + let delegated_amount = u64::from(source_account.delegated_amount) .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; if !self_transfer { - source_account.delegated_amount = delegated_amount.to_le_bytes(); + source_account.delegated_amount = delegated_amount.into(); if delegated_amount == 0 { source_account.delegate = PodCOption::from(None); @@ -135,12 +135,12 @@ pub fn process_transfer( // Moves the tokens. - source_account.amount = remaining_amount.to_le_bytes(); + source_account.amount = remaining_amount.into(); - let destination_amount = u64::from_le_bytes(destination_account.amount) + let destination_amount = u64::from(destination_account.amount) .checked_add(amount) .ok_or(TokenError::Overflow)?; - destination_account.amount = destination_amount.to_le_bytes(); + destination_account.amount = destination_amount.into(); if is_native_mint(&source_account.mint) { let mut source_lamports = source_account_info.try_borrow_mut_lamports()?; From 73f2007dd3df99e61e900f1b26a04fe1ac63bf3d Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 12 Nov 2024 10:16:13 +0000 Subject: [PATCH 269/335] Add workspace dependencies --- p-token/Cargo.toml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 57a8837..eb48f33 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "token-program" version = "0.0.0" -edition = "2021" +edition = { workspace = true } readme = "./README.md" -license-file = "../LICENSE" +license = { workspace = true } +repository = { workspace = true } publish = false [package.metadata.solana] -program-id = "TokenLight111111111111111111111111111111111" +program-id = "Tokenocchio11111111111111111111111111111111" [lib] crate-type = ["cdylib", "lib"] @@ -17,9 +18,9 @@ logging = [] test-sbf = [] [dependencies] -bytemuck = { version="1.18.0", features=["derive"] } -pinocchio = "0.6" -pinocchio-pubkey = "0.2" +bytemuck = { workspace = true } +pinocchio = { workspace = true } +pinocchio-pubkey = { workspace = true } token-interface = { version = "^0", path = "../interface" } [dev-dependencies] From 68da3888fe93d246d5e617e77899447b5669704d Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 12 Nov 2024 12:28:11 +0000 Subject: [PATCH 270/335] Update program ID --- p-token/tests/initialize_account.rs | 2 +- p-token/tests/initialize_mint.rs | 2 +- p-token/tests/mint_to.rs | 2 +- p-token/tests/transfer.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs index 5172b4c..ae678ab 100644 --- a/p-token/tests/initialize_account.rs +++ b/p-token/tests/initialize_account.rs @@ -13,7 +13,7 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "tokenocchio")] #[tokio::test] async fn initialize_account(token_program: Pubkey) { let program_id = Pubkey::new_from_array(token_program::ID); diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 547b53e..6b43870 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -14,7 +14,7 @@ use solana_sdk::{ use token_interface::state::mint::Mint; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "tokenocchio")] #[tokio::test] async fn initialize_mint(token_program: Pubkey) { let program_id = Pubkey::new_from_array(token_program::ID); diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index 897b45d..e57faf2 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -12,7 +12,7 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "tokenocchio")] #[tokio::test] async fn mint_to(token_program: Pubkey) { let program_id = Pubkey::new_from_array(token_program::ID); diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index 287e804..9c40cc0 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -12,7 +12,7 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "token-light")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "tokenocchio")] #[tokio::test] async fn transfer(token_program: Pubkey) { let program_id = Pubkey::new_from_array(token_program::ID); From 7b58a42cfdac49896270f80101680ca9070a3499 Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 12 Nov 2024 12:30:25 +0000 Subject: [PATCH 271/335] Enable rent exempt check --- p-token/src/processor/initialize_account.rs | 8 ++++++-- p-token/src/processor/initialize_mint.rs | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs index f53a8c4..e88a083 100644 --- a/p-token/src/processor/initialize_account.rs +++ b/p-token/src/processor/initialize_account.rs @@ -36,13 +36,17 @@ pub fn process_initialize_account( (new_account_info, mint_info, owner_info.key()) }; - /* TODO: Implement rent exemption + // Check rent-exempt status of the token account. + // + // WIP: This is an expensive check (~400 CU) since it involves floating-point + // operations. Currently we are using a 'scaled' version, which is faster but + // not as precise as the `f64` version when there are decimal places. + let rent = Rent::get()?; if !rent.is_exempt_scaled(new_account_info.lamports(), size_of::()) { return Err(TokenError::NotRentExempt.into()); } - */ let account_data = unsafe { new_account_info.borrow_mut_data_unchecked() }; let account = bytemuck::try_from_bytes_mut::(account_data) diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 15b1545..dca69d8 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -3,6 +3,7 @@ use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, pubkey::{Pubkey, PUBKEY_BYTES}, + sysvars::{rent::Rent, Sysvar}, ProgramResult, }; use std::mem::size_of; @@ -31,14 +32,16 @@ pub fn process_initialize_mint( } // Check rent-exempt status of the mint account. + // + // WIP: This is an expensive check (~400 CU) since it involves floating-point + // operations. Currently we are using a 'scaled' version, which is faster but + // not as precise as the `f64` version when there are decimal places. - /* TODO: Implement rent exemption let rent = Rent::get()?; if !rent.is_exempt_scaled(mint_info.lamports(), size_of::()) { return Err(TokenError::NotRentExempt.into()); } - */ // Initialize the mint. From 080808b48ce1dc404d9b592ef5b5f4504d3e5736 Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 12 Nov 2024 15:44:01 +0000 Subject: [PATCH 272/335] Rename program --- p-token/Cargo.toml | 2 +- p-token/README.md | 4 ++-- p-token/src/lib.rs | 2 +- p-token/tests/initialize_account.rs | 2 +- p-token/tests/initialize_mint.rs | 2 +- p-token/tests/mint_to.rs | 2 +- p-token/tests/transfer.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index eb48f33..1e2af78 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -8,7 +8,7 @@ repository = { workspace = true } publish = false [package.metadata.solana] -program-id = "Tokenocchio11111111111111111111111111111111" +program-id = "PToken1111111111111111111111111111111111111" [lib] crate-type = ["cdylib", "lib"] diff --git a/p-token/README.md b/p-token/README.md index 987b9d8..4fa737c 100644 --- a/p-token/README.md +++ b/p-token/README.md @@ -1,3 +1,3 @@ -# Token +# `p-token` -Your generated Solana program. Have fun! +A `pinocchio`-based Token program. diff --git a/p-token/src/lib.rs b/p-token/src/lib.rs index 44dcf52..3a174fb 100644 --- a/p-token/src/lib.rs +++ b/p-token/src/lib.rs @@ -3,4 +3,4 @@ mod entrypoint; mod processor; -pinocchio_pubkey::declare_id!("Tokenocchio11111111111111111111111111111111"); +pinocchio_pubkey::declare_id!("PToken1111111111111111111111111111111111111"); diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs index ae678ab..bf23bec 100644 --- a/p-token/tests/initialize_account.rs +++ b/p-token/tests/initialize_account.rs @@ -13,7 +13,7 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "tokenocchio")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] #[tokio::test] async fn initialize_account(token_program: Pubkey) { let program_id = Pubkey::new_from_array(token_program::ID); diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 6b43870..694ad64 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -14,7 +14,7 @@ use solana_sdk::{ use token_interface::state::mint::Mint; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "tokenocchio")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] #[tokio::test] async fn initialize_mint(token_program: Pubkey) { let program_id = Pubkey::new_from_array(token_program::ID); diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index e57faf2..841a708 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -12,7 +12,7 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "tokenocchio")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] #[tokio::test] async fn mint_to(token_program: Pubkey) { let program_id = Pubkey::new_from_array(token_program::ID); diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index 9c40cc0..ad13ce3 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -12,7 +12,7 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "tokenocchio")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] #[tokio::test] async fn transfer(token_program: Pubkey) { let program_id = Pubkey::new_from_array(token_program::ID); From ed0a15760b4fc08148d49e12d907a6f5e725c6a6 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 18 Nov 2024 17:07:00 +0000 Subject: [PATCH 273/335] More instructions --- interface/src/instruction.rs | 16 +-- interface/src/lib.rs | 4 + interface/src/state/account.rs | 3 + interface/src/state/mint.rs | 5 + interface/src/state/mod.rs | 9 +- .../state/{multisignature.rs => multisig.rs} | 5 + p-token/src/entrypoint.rs | 82 +++++++++++ p-token/src/processor/approve.rs | 73 ++++++++++ p-token/src/processor/burn.rs | 89 ++++++++++++ p-token/src/processor/close_account.rs | 49 +++++++ p-token/src/processor/freeze_account.rs | 7 + p-token/src/processor/initialize_account.rs | 26 ++-- p-token/src/processor/initialize_mint.rs | 35 +++-- p-token/src/processor/initialize_multisig.rs | 63 +++++++++ p-token/src/processor/mod.rs | 25 +++- p-token/src/processor/revoke.rs | 29 ++++ p-token/src/processor/set_authority.rs | 132 ++++++++++++++++++ p-token/src/processor/thaw_account.rs | 7 + p-token/src/processor/toggle_account_state.rs | 54 +++++++ p-token/tests/approve.rs | 89 ++++++++++++ p-token/tests/burn.rs | 79 +++++++++++ p-token/tests/close_account.rs | 69 +++++++++ p-token/tests/freeze_account.rs | 76 ++++++++++ p-token/tests/initialize_multisig.rs | 79 +++++++++++ p-token/tests/mint_to.rs | 4 +- p-token/tests/revoke.rs | 93 ++++++++++++ p-token/tests/set_authority.rs | 72 ++++++++++ p-token/tests/setup/account.rs | 62 +++++++- p-token/tests/thaw_account.rs | 85 +++++++++++ p-token/tests/transfer.rs | 8 +- 30 files changed, 1380 insertions(+), 49 deletions(-) rename interface/src/state/{multisignature.rs => multisig.rs} (77%) create mode 100644 p-token/src/processor/approve.rs create mode 100644 p-token/src/processor/burn.rs create mode 100644 p-token/src/processor/close_account.rs create mode 100644 p-token/src/processor/freeze_account.rs create mode 100644 p-token/src/processor/initialize_multisig.rs create mode 100644 p-token/src/processor/revoke.rs create mode 100644 p-token/src/processor/set_authority.rs create mode 100644 p-token/src/processor/thaw_account.rs create mode 100644 p-token/src/processor/toggle_account_state.rs create mode 100644 p-token/tests/approve.rs create mode 100644 p-token/tests/burn.rs create mode 100644 p-token/tests/close_account.rs create mode 100644 p-token/tests/freeze_account.rs create mode 100644 p-token/tests/initialize_multisig.rs create mode 100644 p-token/tests/revoke.rs create mode 100644 p-token/tests/set_authority.rs create mode 100644 p-token/tests/thaw_account.rs diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index de69609..c78e6bb 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -1,8 +1,8 @@ //! Instruction types -use pinocchio::{program_error::ProgramError, pubkey::Pubkey}; +use pinocchio::pubkey::Pubkey; -use crate::{error::TokenError, state::PodCOption}; +use crate::state::PodCOption; /// Instructions supported by the token program. #[repr(C)] @@ -506,13 +506,13 @@ impl AuthorityType { } } - pub fn from(index: u8) -> Result { + pub fn from(index: u8) -> Self { match index { - 0 => Ok(AuthorityType::MintTokens), - 1 => Ok(AuthorityType::FreezeAccount), - 2 => Ok(AuthorityType::AccountOwner), - 3 => Ok(AuthorityType::CloseAccount), - _ => Err(TokenError::InvalidInstruction.into()), + 0 => AuthorityType::MintTokens, + 1 => AuthorityType::FreezeAccount, + 2 => AuthorityType::AccountOwner, + 3 => AuthorityType::CloseAccount, + _ => panic!("invalid authority type: {index}"), } } } diff --git a/interface/src/lib.rs b/interface/src/lib.rs index 8c4d430..47c701c 100644 --- a/interface/src/lib.rs +++ b/interface/src/lib.rs @@ -2,3 +2,7 @@ pub mod error; pub mod instruction; pub mod native_mint; pub mod state; + +pub mod program { + pinocchio_pubkey::declare_id!("11111111111111111111111111111111"); +} diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index 73deac4..e88b48d 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -37,6 +37,9 @@ pub struct Account { } impl Account { + /// Size of the `Account` account. + pub const LEN: usize = core::mem::size_of::(); + #[inline] pub fn is_initialized(&self) -> bool { self.state != AccountState::Uninitialized as u8 diff --git a/interface/src/state/mint.rs b/interface/src/state/mint.rs index 2d42391..50896c6 100644 --- a/interface/src/state/mint.rs +++ b/interface/src/state/mint.rs @@ -25,3 +25,8 @@ pub struct Mint { /// Optional authority to freeze token accounts. pub freeze_authority: PodCOption, } + +impl Mint { + /// Size of the `Mint` account. + pub const LEN: usize = core::mem::size_of::(); +} diff --git a/interface/src/state/mod.rs b/interface/src/state/mod.rs index c26918b..a0f8d9b 100644 --- a/interface/src/state/mod.rs +++ b/interface/src/state/mod.rs @@ -4,7 +4,7 @@ use bytemuck::{Pod, Zeroable}; pub mod account; pub mod mint; -pub mod multisignature; +pub mod multisig; #[repr(C)] #[derive(Clone, Copy, Debug, Default, PartialEq)] @@ -40,6 +40,13 @@ impl PodCOption { pub const SOME: [u8; 4] = [1, 0, 0, 0]; + pub fn some(value: T) -> Self { + Self { + tag: [1, 0, 0, 0], + value, + } + } + /// Returns `true` if the option is a `None` value. #[inline] pub fn is_none(&self) -> bool { diff --git a/interface/src/state/multisignature.rs b/interface/src/state/multisig.rs similarity index 77% rename from interface/src/state/multisignature.rs rename to interface/src/state/multisig.rs index 4bf8a20..d34d2e6 100644 --- a/interface/src/state/multisignature.rs +++ b/interface/src/state/multisig.rs @@ -24,4 +24,9 @@ pub struct Multisig { impl Multisig { pub const LEN: usize = core::mem::size_of::(); + + /// Utility function that checks index is between [`MIN_SIGNERS`] and [`MAX_SIGNERS`]. + pub fn is_valid_signer_index(index: usize) -> bool { + (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) + } } diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 6683771..1e4345e 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -4,9 +4,17 @@ use pinocchio::{ }; use crate::processor::{ + approve::process_approve, + burn::process_burn, + close_account::process_close_account, + freeze_account::process_freeze_account, initialize_account::process_initialize_account, initialize_mint::{process_initialize_mint, InitializeMint}, + initialize_multisig::process_initialize_multisig, mint_to::process_mint_to, + revoke::process_revoke, + set_authority::{process_set_authority, SetAuthority}, + thaw_account::process_thaw_account, transfer::process_transfer, }; @@ -34,6 +42,15 @@ pub fn process_instruction( process_initialize_account(program_id, accounts, None, true) } + // 2 - InitializeMultisig + Some((&2, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeMultisig"); + + let m = data.first().ok_or(ProgramError::InvalidInstructionData)?; + + process_initialize_multisig(accounts, *m, true) + } // 3 - Transfer Some((&3, data)) => { #[cfg(feature = "logging")] @@ -46,6 +63,38 @@ pub fn process_instruction( process_transfer(program_id, accounts, amount, None) } + // 4 - Approve + Some((&4, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: Approve"); + + let amount = u64::from_le_bytes( + data.try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + process_approve(program_id, accounts, amount, None) + } + // 5 - Revoke + Some((&5, _)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: Revoke"); + + process_revoke(program_id, accounts) + } + // 6 - SetAuthority + Some((&6, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: SetAuthority"); + + let instruction = SetAuthority::try_from_bytes(data)?; + process_set_authority( + program_id, + accounts, + instruction.authority_type, + instruction.new_authority, + ) + } // 7 - InitializeMint Some((&7, data)) => { #[cfg(feature = "logging")] @@ -58,6 +107,39 @@ pub fn process_instruction( process_mint_to(program_id, accounts, amount, None) } + // 8 - Burn + Some((&8, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: Burn"); + + let amount = u64::from_le_bytes( + data.try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + process_burn(program_id, accounts, amount, None) + } + // 9 - CloseAccount + Some((&9, _)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: CloseAccount"); + + process_close_account(program_id, accounts) + } + // 10 - FreezeAccount + Some((&10, _)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: FreezeAccount"); + + process_freeze_account(program_id, accounts) + } + // 10 - ThawAccount + Some((&11, _)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: ThawAccount"); + + process_thaw_account(program_id, accounts) + } _ => Err(ProgramError::InvalidInstructionData), } } diff --git a/p-token/src/processor/approve.rs b/p-token/src/processor/approve.rs new file mode 100644 index 0000000..ca09471 --- /dev/null +++ b/p-token/src/processor/approve.rs @@ -0,0 +1,73 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{ + error::TokenError, + state::{account::Account, mint::Mint, PodCOption}, +}; + +use super::validate_owner; + +pub fn process_approve( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + expected_decimals: Option, +) -> ProgramResult { + let (source_account_info, expected_mint_info, delegate_info, owner_info, remaining) = + if let Some(expected_decimals) = expected_decimals { + let [source_account_info, expected_mint_info, delegate_info, owner_info, remaning @ ..] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + ( + source_account_info, + Some((expected_mint_info, expected_decimals)), + delegate_info, + owner_info, + remaning, + ) + } else { + let [source_account_info, delegate_info, owner_info, remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + ( + source_account_info, + None, + delegate_info, + owner_info, + remaning, + ) + }; + + let source_account = bytemuck::try_from_bytes_mut::(unsafe { + source_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + if let Some((mint_info, expected_decimals)) = expected_mint_info { + if mint_info.key() != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mint = bytemuck::try_from_bytes::(unsafe { mint_info.borrow_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + validate_owner(program_id, &source_account.owner, owner_info, remaining)?; + + source_account.delegate = PodCOption::some(*delegate_info.key()); + source_account.delegated_amount = amount.into(); + + Ok(()) +} diff --git a/p-token/src/processor/burn.rs b/p-token/src/processor/burn.rs new file mode 100644 index 0000000..f0a1c54 --- /dev/null +++ b/p-token/src/processor/burn.rs @@ -0,0 +1,89 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{ + error::TokenError, + state::{account::Account, mint::Mint}, +}; + +use super::{check_account_owner, is_owned_by_system_program_or_incinerator, validate_owner}; + +/// Processes a [Burn](enum.TokenInstruction.html) instruction. +pub fn process_burn( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + expected_decimals: Option, +) -> ProgramResult { + let [source_account_info, mint_info, authority_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + // Safety: There are no conflicting borrows – the source account is only borrowed once. + let source_account = bytemuck::try_from_bytes_mut::(unsafe { + source_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + if source_account.is_native.is_some() { + return Err(TokenError::NativeNotSupported.into()); + } + + // Ensure the source account has the sufficient amount. This is done before + // the value is updated on the account. + let updated_source_amount = u64::from(source_account.amount) + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + + // Safety: There are no conflicting borrows – the mint account is only borrowed once. + let mint = + bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if mint_info.key() != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + if !is_owned_by_system_program_or_incinerator(&source_account.owner) { + match source_account.delegate.as_ref() { + Some(delegate) if authority_info.key() == delegate => { + validate_owner(program_id, delegate, authority_info, remaining)?; + + let delegated_amount = u64::from(source_account.delegated_amount) + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + source_account.delegated_amount = delegated_amount.into(); + + if delegated_amount == 0 { + source_account.delegate.clear(); + } + } + _ => { + validate_owner(program_id, &source_account.owner, authority_info, remaining)?; + } + } + } + + if amount == 0 { + check_account_owner(program_id, source_account_info)?; + check_account_owner(program_id, mint_info)?; + } + + source_account.amount = updated_source_amount.into(); + + let mint_supply = u64::from(mint.supply) + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + mint.supply = mint_supply.into(); + + Ok(()) +} diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs new file mode 100644 index 0000000..b20535c --- /dev/null +++ b/p-token/src/processor/close_account.rs @@ -0,0 +1,49 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{error::TokenError, state::account::Account}; + +use super::{is_owned_by_system_program_or_incinerator, validate_owner, INCINERATOR_ID}; + +/// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. +pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let [source_account_info, destination_account_info, authority_info, remaining @ ..] = accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if source_account_info.key() == destination_account_info.key() { + return Err(ProgramError::InvalidAccountData); + } + + let source_account = + bytemuck::try_from_bytes::(unsafe { source_account_info.borrow_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if source_account.is_native.is_none() && source_account.amount() != 0 { + return Err(TokenError::NonNativeHasBalance.into()); + } + + let authority = source_account + .close_authority + .get() + .unwrap_or(source_account.owner); + + if !is_owned_by_system_program_or_incinerator(source_account_info.owner()) { + validate_owner(program_id, &authority, authority_info, remaining)?; + } else if destination_account_info.key() != &INCINERATOR_ID { + return Err(ProgramError::InvalidAccountData); + } + + let destination_starting_lamports = destination_account_info.lamports(); + unsafe { + // Moves the lamports to the destination account and closes the source account. + *destination_account_info.borrow_mut_lamports_unchecked() = destination_starting_lamports + .checked_add(source_account_info.lamports()) + .ok_or(TokenError::Overflow)?; + + source_account_info.close(); + } + + Ok(()) +} diff --git a/p-token/src/processor/freeze_account.rs b/p-token/src/processor/freeze_account.rs new file mode 100644 index 0000000..e8cb7b5 --- /dev/null +++ b/p-token/src/processor/freeze_account.rs @@ -0,0 +1,7 @@ +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; + +use super::toggle_account_state::process_toggle_account_state; + +pub fn process_freeze_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + process_toggle_account_state(program_id, accounts, true) +} diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs index e88a083..ac8efa9 100644 --- a/p-token/src/processor/initialize_account.rs +++ b/p-token/src/processor/initialize_account.rs @@ -22,29 +22,31 @@ pub fn process_initialize_account( program_id: &Pubkey, accounts: &[AccountInfo], owner: Option<&Pubkey>, - _rent_sysvar_account: bool, + rent_sysvar_account: bool, ) -> ProgramResult { - let (new_account_info, mint_info, owner) = if let Some(owner) = owner { - let [new_account_info, mint_info, _remaning @ ..] = accounts else { + let (new_account_info, mint_info, owner, remaning) = if let Some(owner) = owner { + let [new_account_info, mint_info, remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - (new_account_info, mint_info, owner) + (new_account_info, mint_info, owner, remaning) } else { - let [new_account_info, mint_info, owner_info, _remaning @ ..] = accounts else { + let [new_account_info, mint_info, owner_info, remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - (new_account_info, mint_info, owner_info.key()) + (new_account_info, mint_info, owner_info.key(), remaning) }; // Check rent-exempt status of the token account. - // - // WIP: This is an expensive check (~400 CU) since it involves floating-point - // operations. Currently we are using a 'scaled' version, which is faster but - // not as precise as the `f64` version when there are decimal places. - let rent = Rent::get()?; + let is_exempt = if rent_sysvar_account { + let rent_sysvar_info = remaning.first().ok_or(ProgramError::NotEnoughAccountKeys)?; + let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + rent.is_exempt(new_account_info.lamports(), size_of::()) + } else { + Rent::get()?.is_exempt(new_account_info.lamports(), size_of::()) + }; - if !rent.is_exempt_scaled(new_account_info.lamports(), size_of::()) { + if !is_exempt { return Err(TokenError::NotRentExempt.into()); } diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index dca69d8..180e8b5 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -15,31 +15,38 @@ use token_interface::{ pub fn process_initialize_mint( accounts: &[AccountInfo], args: &InitializeMint, - _rent_sysvar_account: bool, + rent_sysvar_account: bool, ) -> ProgramResult { - // Validate the mint account. - - let [mint_info, _remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); + let (mint_info, rent_sysvar_info) = if rent_sysvar_account { + let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (mint_info, Some(rent_sysvar_info)) + } else { + let [mint_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (mint_info, None) }; - let mint_data = unsafe { mint_info.borrow_mut_data_unchecked() }; - let mint = bytemuck::try_from_bytes_mut::(mint_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let mint = + bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; if mint.is_initialized.into() { return Err(TokenError::AlreadyInUse.into()); } // Check rent-exempt status of the mint account. - // - // WIP: This is an expensive check (~400 CU) since it involves floating-point - // operations. Currently we are using a 'scaled' version, which is faster but - // not as precise as the `f64` version when there are decimal places. - let rent = Rent::get()?; + let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { + let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + rent.is_exempt(mint_info.lamports(), size_of::()) + } else { + Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) + }; - if !rent.is_exempt_scaled(mint_info.lamports(), size_of::()) { + if !is_exempt { return Err(TokenError::NotRentExempt.into()); } diff --git a/p-token/src/processor/initialize_multisig.rs b/p-token/src/processor/initialize_multisig.rs new file mode 100644 index 0000000..53fc939 --- /dev/null +++ b/p-token/src/processor/initialize_multisig.rs @@ -0,0 +1,63 @@ +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, +}; +use token_interface::{error::TokenError, state::multisig::Multisig}; + +pub fn process_initialize_multisig( + accounts: &[AccountInfo], + m: u8, + rent_sysvar_account: bool, +) -> ProgramResult { + let (multisig_info, rent_sysvar_info, remaining) = if rent_sysvar_account { + let [multisig_info, rent_sysvar_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (multisig_info, Some(rent_sysvar_info), remaining) + } else { + let [multisig_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (multisig_info, None, remaining) + }; + + let multisig_info_data_len = multisig_info.data_len(); + + let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { + let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) + } else { + Rent::get()?.is_exempt(multisig_info.lamports(), multisig_info_data_len) + }; + + if !is_exempt { + return Err(TokenError::NotRentExempt.into()); + } + + let multisig = bytemuck::try_from_bytes_mut::(unsafe { + multisig_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if multisig.is_initialized.into() { + return Err(TokenError::AlreadyInUse.into()); + } + + multisig.m = m; + multisig.n = remaining.len() as u8; + + if !Multisig::is_valid_signer_index(multisig.n as usize) { + return Err(TokenError::InvalidNumberOfProvidedSigners.into()); + } + if !Multisig::is_valid_signer_index(multisig.m as usize) { + return Err(TokenError::InvalidNumberOfRequiredSigners.into()); + } + for (i, signer_info) in remaining.iter().enumerate() { + multisig.signers[i] = *signer_info.key(); + } + multisig.is_initialized = true.into(); + + Ok(()) +} diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index d741cb9..c3ef040 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -3,13 +3,36 @@ use pinocchio::{ }; use token_interface::{ error::TokenError, - state::multisignature::{Multisig, MAX_SIGNERS}, + state::multisig::{Multisig, MAX_SIGNERS}, }; +pub mod approve; +pub mod burn; +pub mod close_account; +pub mod freeze_account; pub mod initialize_account; pub mod initialize_mint; +pub mod initialize_multisig; pub mod mint_to; +pub mod revoke; +pub mod set_authority; +pub mod thaw_account; pub mod transfer; +// Private processor to toggle the account state. This logic is reused by the +// freeze and thaw account instructions. +mod toggle_account_state; + +/// Incinerator address. +const INCINERATOR_ID: Pubkey = + pinocchio_pubkey::pubkey!("1nc1nerator11111111111111111111111111111111"); + +/// System program id. +const SYSTEM_PROGRAM_ID: Pubkey = pinocchio_pubkey::pubkey!("11111111111111111111111111111111"); + +#[inline(always)] +pub fn is_owned_by_system_program_or_incinerator(owner: &Pubkey) -> bool { + SYSTEM_PROGRAM_ID == *owner || INCINERATOR_ID == *owner +} /// Checks that the account is owned by the expected program. #[inline(always)] diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs new file mode 100644 index 0000000..49de485 --- /dev/null +++ b/p-token/src/processor/revoke.rs @@ -0,0 +1,29 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{error::TokenError, state::account::Account}; + +use super::validate_owner; + +/// Processes an [Revoke](enum.TokenInstruction.html) instruction. +pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let [source_account_info, owner_info, remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + let source_account = bytemuck::try_from_bytes_mut::(unsafe { + source_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + validate_owner(program_id, &source_account.owner, owner_info, remaning)?; + + source_account.delegate.clear(); + source_account.delegated_amount = 0.into(); + + Ok(()) +} diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs new file mode 100644 index 0000000..e2438e8 --- /dev/null +++ b/p-token/src/processor/set_authority.rs @@ -0,0 +1,132 @@ +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::{Pubkey, PUBKEY_BYTES}, + ProgramResult, +}; +use token_interface::{ + error::TokenError, + instruction::AuthorityType, + state::{account::Account, mint::Mint, PodCOption}, +}; + +use super::validate_owner; + +pub fn process_set_authority( + program_id: &Pubkey, + accounts: &[AccountInfo], + authority_type: AuthorityType, + new_authority: Option<&Pubkey>, +) -> ProgramResult { + let [account_info, authority_info, remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if account_info.data_len() == Account::LEN { + let account = bytemuck::try_from_bytes_mut::(unsafe { + account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + match authority_type { + AuthorityType::AccountOwner => { + validate_owner(program_id, &account.owner, authority_info, remaning)?; + + if let Some(authority) = new_authority { + account.owner = *authority; + } else { + return Err(TokenError::InvalidInstruction.into()); + } + + account.delegate.clear(); + account.delegated_amount = 0.into(); + + if account.is_native.is_some() { + account.close_authority.clear(); + } + } + AuthorityType::CloseAccount => { + let authority = account.close_authority.as_ref().unwrap_or(&account.owner); + validate_owner(program_id, authority, authority_info, remaning)?; + account.close_authority = PodCOption::from(new_authority.copied()); + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); + } + } + } else if account_info.data_len() == Mint::LEN { + let mint = bytemuck::try_from_bytes_mut::(unsafe { + account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + match authority_type { + AuthorityType::MintTokens => { + // Once a mint's supply is fixed, it cannot be undone by setting a new + // mint_authority + let mint_authority = mint + .mint_authority + .as_ref() + .ok_or(TokenError::FixedSupply)?; + + validate_owner(program_id, mint_authority, authority_info, remaning)?; + mint.mint_authority = PodCOption::from(new_authority.copied()); + } + AuthorityType::FreezeAccount => { + // Once a mint's freeze authority is disabled, it cannot be re-enabled by + // setting a new freeze_authority + let freeze_authority = mint + .freeze_authority + .as_ref() + .ok_or(TokenError::MintCannotFreeze)?; + + validate_owner(program_id, freeze_authority, authority_info, remaning)?; + mint.freeze_authority = PodCOption::from(new_authority.copied()); + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); + } + } + } else { + return Err(ProgramError::InvalidArgument); + } + + Ok(()) +} + +/// Instruction data for the `InitializeMint` instruction. +pub struct SetAuthority<'a> { + pub authority_type: AuthorityType, + + /// New authority. + pub new_authority: Option<&'a Pubkey>, +} + +impl<'a> SetAuthority<'a> { + pub fn try_from_bytes(data: &'a [u8]) -> Result { + // We expect the data to be at least the size of the u8 (authority_type) + // plus one byte for the authority option. + if data.len() <= 2 { + return Err(ProgramError::InvalidInstructionData); + } + + let (authority_type, remaining) = data.split_at(1); + + let new_authority = match remaining.split_first() { + Some((&0, _)) => None, + Some((&1, pubkey)) if pubkey.len() == PUBKEY_BYTES => { + Some(bytemuck::from_bytes::(pubkey)) + } + _ => return Err(ProgramError::InvalidInstructionData), + }; + + Ok(Self { + authority_type: AuthorityType::from(authority_type[0]), + new_authority, + }) + } +} diff --git a/p-token/src/processor/thaw_account.rs b/p-token/src/processor/thaw_account.rs new file mode 100644 index 0000000..b432877 --- /dev/null +++ b/p-token/src/processor/thaw_account.rs @@ -0,0 +1,7 @@ +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; + +use super::toggle_account_state::process_toggle_account_state; + +pub fn process_thaw_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + process_toggle_account_state(program_id, accounts, false) +} diff --git a/p-token/src/processor/toggle_account_state.rs b/p-token/src/processor/toggle_account_state.rs new file mode 100644 index 0000000..aaac762 --- /dev/null +++ b/p-token/src/processor/toggle_account_state.rs @@ -0,0 +1,54 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{ + error::TokenError, + state::{ + account::{Account, AccountState}, + mint::Mint, + }, +}; + +use super::validate_owner; + +#[inline(always)] +pub fn process_toggle_account_state( + program_id: &Pubkey, + accounts: &[AccountInfo], + freeze: bool, +) -> ProgramResult { + let [source_account_info, mint_info, authority_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + let source_account = bytemuck::try_from_bytes_mut::(unsafe { + source_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { + return Err(TokenError::InvalidState.into()); + } + if source_account.is_native.is_some() { + return Err(TokenError::NativeNotSupported.into()); + } + if mint_info.key() != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mint = bytemuck::try_from_bytes::(unsafe { mint_info.borrow_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + match mint.freeze_authority.as_ref() { + Option::Some(authority) => validate_owner(program_id, authority, authority_info, remaining), + Option::None => Err(TokenError::MintCannotFreeze.into()), + }?; + + source_account.state = if freeze { + AccountState::Frozen + } else { + AccountState::Initialized + } as u8; + + Ok(()) +} diff --git a/p-token/tests/approve.rs b/p-token/tests/approve.rs new file mode 100644 index 0000000..4319b14 --- /dev/null +++ b/p-token/tests/approve.rs @@ -0,0 +1,89 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn approve(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account with 100 tokens. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + mint::mint( + &mut context, + &mint, + &account, + &mint_authority, + 100, + &token_program, + ) + .await + .unwrap(); + + // When we approve a delegate. + + let delegate = Pubkey::new_unique(); + + let mut approve_ix = spl_token::instruction::approve( + &spl_token::ID, + &account, + &delegate, + &owner.pubkey(), + &[], + 50, + ) + .unwrap(); + approve_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[approve_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the account should have the delegate and delegated amount. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.delegate.is_some()); + assert!(account.delegate.unwrap() == delegate); + assert!(account.delegated_amount == 50); +} diff --git a/p-token/tests/burn.rs b/p-token/tests/burn.rs new file mode 100644 index 0000000..baa12a9 --- /dev/null +++ b/p-token/tests/burn.rs @@ -0,0 +1,79 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn burn(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account with 100 tokens. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + mint::mint( + &mut context, + &mint, + &account, + &mint_authority, + 100, + &token_program, + ) + .await + .unwrap(); + + // When we burn 50 tokens. + + let mut burn_ix = + spl_token::instruction::burn(&spl_token::ID, &account, &mint, &owner.pubkey(), &[], 50) + .unwrap(); + burn_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[burn_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the account should have 50 tokens remaining. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.amount == 50); +} diff --git a/p-token/tests/close_account.rs b/p-token/tests/close_account.rs new file mode 100644 index 0000000..a1633b3 --- /dev/null +++ b/p-token/tests/close_account.rs @@ -0,0 +1,69 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn close_account(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + let token_account = context.banks_client.get_account(account).await.unwrap(); + assert!(token_account.is_some()); + + // When we close the account. + + let mut close_account_ix = spl_token::instruction::close_account( + &spl_token::ID, + &account, + &owner.pubkey(), + &owner.pubkey(), + &[], + ) + .unwrap(); + close_account_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[close_account_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account must not exist. + + let token_account = context.banks_client.get_account(account).await.unwrap(); + assert!(token_account.is_none()); +} diff --git a/p-token/tests/freeze_account.rs b/p-token/tests/freeze_account.rs new file mode 100644 index 0000000..5883c20 --- /dev/null +++ b/p-token/tests/freeze_account.rs @@ -0,0 +1,76 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; +use spl_token::state::AccountState; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn freeze_account(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Keypair::new(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority.pubkey()), + &token_program, + ) + .await + .unwrap(); + + // And a token account. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + let token_account = context.banks_client.get_account(account).await.unwrap(); + assert!(token_account.is_some()); + + // When we freeze the account. + + let mut freeze_account_ix = spl_token::instruction::freeze_account( + &spl_token::ID, + &account, + &mint, + &freeze_authority.pubkey(), + &[], + ) + .unwrap(); + freeze_account_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[freeze_account_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &freeze_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the account is frozen. + + let token_account = context.banks_client.get_account(account).await.unwrap(); + assert!(token_account.is_some()); + + let token_account = token_account.unwrap(); + let token_account = spl_token::state::Account::unpack(&token_account.data).unwrap(); + + assert_eq!(token_account.state, AccountState::Frozen); +} diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs new file mode 100644 index 0000000..39fd6b9 --- /dev/null +++ b/p-token/tests/initialize_multisig.rs @@ -0,0 +1,79 @@ +#![cfg(feature = "test-sbf")] + +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; +use spl_token::state::Multisig; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn initialize_multisig(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given an account + + let multisig = Keypair::new(); + let signer1 = Pubkey::new_unique(); + let signer2 = Pubkey::new_unique(); + let signer3 = Pubkey::new_unique(); + let signers = vec![&signer1, &signer2, &signer3]; + + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_multisig( + &spl_token::ID, + &multisig.pubkey(), + &signers, + 2, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new multisig account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &multisig.pubkey(), + rent.minimum_balance(Multisig::LEN), + Multisig::LEN as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &multisig], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the multisig has the correct data. + + let account = context + .banks_client + .get_account(multisig.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let multisig = spl_token::state::Multisig::unpack(&account.data).unwrap(); + + assert!(multisig.is_initialized); + assert_eq!(multisig.n, 3); + assert_eq!(multisig.m, 2); +} diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index 841a708..e343fb7 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -38,9 +38,7 @@ async fn mint_to(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program) - .await - .unwrap(); + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; // When we mint tokens to it. diff --git a/p-token/tests/revoke.rs b/p-token/tests/revoke.rs new file mode 100644 index 0000000..ebdca5e --- /dev/null +++ b/p-token/tests/revoke.rs @@ -0,0 +1,93 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn revoke(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account with 100 tokens. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + mint::mint( + &mut context, + &mint, + &account, + &mint_authority, + 100, + &token_program, + ) + .await + .unwrap(); + + // And 50 tokens delegated. + + let delegate = Pubkey::new_unique(); + + account::approve( + &mut context, + &account, + &delegate, + &owner, + 50, + &token_program, + ) + .await; + + // When we revoke the delegation. + + let mut revoke_ix = + spl_token::instruction::revoke(&spl_token::ID, &account, &owner.pubkey(), &[]).unwrap(); + revoke_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[revoke_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the account should not have a delegate nor delegated amount. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.delegate.is_none()); + assert!(account.delegated_amount == 0); +} diff --git a/p-token/tests/set_authority.rs b/p-token/tests/set_authority.rs new file mode 100644 index 0000000..4718564 --- /dev/null +++ b/p-token/tests/set_authority.rs @@ -0,0 +1,72 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::mint; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_option::COption, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; +use spl_token::instruction::AuthorityType; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn set_authority(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Keypair::new(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority.pubkey()), + &token_program, + ) + .await + .unwrap(); + + // When we set a new freeze authority. + + let new_authority = Pubkey::new_unique(); + + let mut set_authority_ix = spl_token::instruction::set_authority( + &spl_token::ID, + &mint, + Some(&new_authority), + AuthorityType::FreezeAccount, + &freeze_authority.pubkey(), + &[], + ) + .unwrap(); + set_authority_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[set_authority_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &freeze_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the account should have the delegate and delegated amount. + + let account = context.banks_client.get_account(mint).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let mint = spl_token::state::Mint::unpack(&account.data).unwrap(); + + assert!(mint.freeze_authority == COption::Some(new_authority)); +} diff --git a/p-token/tests/setup/account.rs b/p-token/tests/setup/account.rs index d43d94f..cb2a097 100644 --- a/p-token/tests/setup/account.rs +++ b/p-token/tests/setup/account.rs @@ -1,7 +1,7 @@ use solana_program_test::ProgramTestContext; use solana_sdk::{ - program_error::ProgramError, pubkey::Pubkey, signature::Keypair, signer::Signer, - system_instruction, transaction::Transaction, + pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, + transaction::Transaction, }; pub async fn initialize( @@ -9,7 +9,7 @@ pub async fn initialize( mint: &Pubkey, owner: &Pubkey, program_id: &Pubkey, -) -> Result { +) -> Pubkey { let account = Keypair::new(); let account_size = 165; @@ -39,5 +39,59 @@ pub async fn initialize( ); context.banks_client.process_transaction(tx).await.unwrap(); - Ok(account.pubkey()) + account.pubkey() +} + +pub async fn approve( + context: &mut ProgramTestContext, + account: &Pubkey, + delegate: &Pubkey, + owner: &Keypair, + amount: u64, + program_id: &Pubkey, +) { + let mut approve_ix = spl_token::instruction::approve( + &spl_token::ID, + account, + delegate, + &owner.pubkey(), + &[], + amount, + ) + .unwrap(); + approve_ix.program_id = *program_id; + + let tx = Transaction::new_signed_with_payer( + &[approve_ix], + Some(&context.payer.pubkey()), + &[&context.payer, owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); +} + +pub async fn freeze( + context: &mut ProgramTestContext, + account: &Pubkey, + mint: &Pubkey, + freeze_authority: &Keypair, + program_id: &Pubkey, +) { + let mut freeze_account_ix = spl_token::instruction::freeze_account( + &spl_token::ID, + account, + mint, + &freeze_authority.pubkey(), + &[], + ) + .unwrap(); + freeze_account_ix.program_id = *program_id; + + let tx = Transaction::new_signed_with_payer( + &[freeze_account_ix], + Some(&context.payer.pubkey()), + &[&context.payer, freeze_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); } diff --git a/p-token/tests/thaw_account.rs b/p-token/tests/thaw_account.rs new file mode 100644 index 0000000..833459c --- /dev/null +++ b/p-token/tests/thaw_account.rs @@ -0,0 +1,85 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; +use spl_token::state::AccountState; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn thaw_account(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Keypair::new(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority.pubkey()), + &token_program, + ) + .await + .unwrap(); + + // And a frozen token account. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + let token_account = context.banks_client.get_account(account).await.unwrap(); + assert!(token_account.is_some()); + + account::freeze( + &mut context, + &account, + &mint, + &freeze_authority, + &token_program, + ) + .await; + + // When we thaw the account. + + let mut thaw_account_ix = spl_token::instruction::thaw_account( + &spl_token::ID, + &account, + &mint, + &freeze_authority.pubkey(), + &[], + ) + .unwrap(); + thaw_account_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[thaw_account_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &freeze_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the account is frozen. + + let token_account = context.banks_client.get_account(account).await.unwrap(); + assert!(token_account.is_some()); + + let token_account = token_account.unwrap(); + let token_account = spl_token::state::Account::unpack(&token_account.data).unwrap(); + + assert_eq!(token_account.state, AccountState::Initialized); +} diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index ad13ce3..70e56b4 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -38,9 +38,7 @@ async fn transfer(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program) - .await - .unwrap(); + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; mint::mint( &mut context, @@ -58,9 +56,7 @@ async fn transfer(token_program: Pubkey) { let destination = Pubkey::new_unique(); let destination_account = - account::initialize(&mut context, &mint, &destination, &token_program) - .await - .unwrap(); + account::initialize(&mut context, &mint, &destination, &token_program).await; let mut transfer_ix = spl_token::instruction::transfer( &spl_token::ID, From 4b1f886bada9c0d612fe104e5466e8b5d06f03d5 Mon Sep 17 00:00:00 2001 From: febo Date: Wed, 20 Nov 2024 22:18:54 +0000 Subject: [PATCH 274/335] Few more instructions --- p-token/src/entrypoint.rs | 83 ++++++++++++++++- p-token/src/processor/approve_checked.rs | 47 ++++++++++ p-token/src/processor/burn_checked.rs | 47 ++++++++++ p-token/src/processor/initialize_account2.rs | 12 +++ p-token/src/processor/initialize_account3.rs | 12 +++ p-token/src/processor/initialize_mint.rs | 54 +++++++++-- p-token/src/processor/initialize_mint2.rs | 7 ++ p-token/src/processor/initialize_multisig2.rs | 7 ++ p-token/src/processor/mint_to_checked.rs | 47 ++++++++++ p-token/src/processor/mod.rs | 8 ++ p-token/src/processor/transfer.rs | 19 ++-- p-token/src/processor/transfer_checked.rs | 47 ++++++++++ p-token/tests/approve_checked.rs | 91 ++++++++++++++++++ p-token/tests/burn_checked.rs | 86 +++++++++++++++++ p-token/tests/initialize_account2.rs | 93 +++++++++++++++++++ p-token/tests/initialize_account3.rs | 93 +++++++++++++++++++ p-token/tests/initialize_mint2.rs | 83 +++++++++++++++++ p-token/tests/initialize_multisig2.rs | 79 ++++++++++++++++ p-token/tests/mint_to_checked.rs | 76 +++++++++++++++ p-token/tests/transfer_checked.rs | 92 ++++++++++++++++++ 20 files changed, 1068 insertions(+), 15 deletions(-) create mode 100644 p-token/src/processor/approve_checked.rs create mode 100644 p-token/src/processor/burn_checked.rs create mode 100644 p-token/src/processor/initialize_account2.rs create mode 100644 p-token/src/processor/initialize_account3.rs create mode 100644 p-token/src/processor/initialize_mint2.rs create mode 100644 p-token/src/processor/initialize_multisig2.rs create mode 100644 p-token/src/processor/mint_to_checked.rs create mode 100644 p-token/src/processor/transfer_checked.rs create mode 100644 p-token/tests/approve_checked.rs create mode 100644 p-token/tests/burn_checked.rs create mode 100644 p-token/tests/initialize_account2.rs create mode 100644 p-token/tests/initialize_account3.rs create mode 100644 p-token/tests/initialize_mint2.rs create mode 100644 p-token/tests/initialize_multisig2.rs create mode 100644 p-token/tests/mint_to_checked.rs create mode 100644 p-token/tests/transfer_checked.rs diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 1e4345e..0f6224a 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -5,17 +5,25 @@ use pinocchio::{ use crate::processor::{ approve::process_approve, + approve_checked::{process_approve_checked, ApproveChecked}, burn::process_burn, + burn_checked::{process_burn_checked, BurnChecked}, close_account::process_close_account, freeze_account::process_freeze_account, initialize_account::process_initialize_account, + initialize_account2::process_initialize_account2, + initialize_account3::process_initialize_account3, initialize_mint::{process_initialize_mint, InitializeMint}, + initialize_mint2::process_initialize_mint2, initialize_multisig::process_initialize_multisig, + initialize_multisig2::process_initialize_multisig2, mint_to::process_mint_to, + mint_to_checked::{process_mint_to_checked, MintToChecked}, revoke::process_revoke, set_authority::{process_set_authority, SetAuthority}, thaw_account::process_thaw_account, transfer::process_transfer, + transfer_checked::{process_transfer_checked, TransferChecked}, }; entrypoint!(process_instruction); @@ -33,6 +41,7 @@ pub fn process_instruction( pinocchio::msg!("Instruction: InitializeMint"); let instruction = InitializeMint::try_from_bytes(data)?; + process_initialize_mint(accounts, &instruction, true) } // 1 - InitializeAccount @@ -133,13 +142,85 @@ pub fn process_instruction( process_freeze_account(program_id, accounts) } - // 10 - ThawAccount + // 11 - ThawAccount Some((&11, _)) => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ThawAccount"); process_thaw_account(program_id, accounts) } + // 12 - TransferChecked + Some((&12, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: TransferChecked"); + + let args = TransferChecked::try_from_bytes(data)?; + + process_transfer_checked(program_id, accounts, args.amount(), args.decimals()) + } + // 13 - ApproveChecked + Some((&13, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: ApproveChecked"); + + let args = ApproveChecked::try_from_bytes(data)?; + + process_approve_checked(program_id, accounts, args.amount(), args.decimals()) + } + // 14 - MintToChecked + Some((&14, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: MintToChecked"); + + let args = MintToChecked::try_from_bytes(data)?; + + process_mint_to_checked(program_id, accounts, args.amount(), args.decimals()) + } + // 15 - BurnChecked + Some((&15, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: BurnChecked"); + + let args = BurnChecked::try_from_bytes(data)?; + + process_burn_checked(program_id, accounts, args.amount(), args.decimals()) + } + // 16 - InitializeAccount2 + Some((&16, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeAccount2"); + + let owner = unsafe { &*(data.as_ptr() as *const Pubkey) }; + + process_initialize_account2(program_id, accounts, owner) + } + // 18 - InitializeAccount3 + Some((&18, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeAccount3"); + + let owner = unsafe { &*(data.as_ptr() as *const Pubkey) }; + + process_initialize_account3(program_id, accounts, owner) + } + // 19 - InitializeMultisig2 + Some((&19, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeMultisig2"); + + let m = data.first().ok_or(ProgramError::InvalidInstructionData)?; + + process_initialize_multisig2(accounts, *m) + } + // 20 - InitializeMint2 + Some((&20, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeMint2"); + + let instruction = InitializeMint::try_from_bytes(data)?; + + process_initialize_mint2(accounts, &instruction) + } _ => Err(ProgramError::InvalidInstructionData), } } diff --git a/p-token/src/processor/approve_checked.rs b/p-token/src/processor/approve_checked.rs new file mode 100644 index 0000000..8ce145b --- /dev/null +++ b/p-token/src/processor/approve_checked.rs @@ -0,0 +1,47 @@ +use std::marker::PhantomData; + +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; + +use super::approve::process_approve; + +#[inline(always)] +pub fn process_approve_checked( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + decimals: u8, +) -> ProgramResult { + process_approve(program_id, accounts, amount, Some(decimals)) +} + +pub struct ApproveChecked<'a> { + raw: *const u8, + + _data: PhantomData<&'a [u8]>, +} + +impl ApproveChecked<'_> { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != 9 { + return Err(ProgramError::InvalidInstructionData); + } + + Ok(ApproveChecked { + raw: bytes.as_ptr(), + _data: PhantomData, + }) + } + + pub fn amount(&self) -> u64 { + unsafe { + let amount = self.raw as *const u64; + amount.read_unaligned() + } + } + + pub fn decimals(&self) -> u8 { + unsafe { *self.raw.add(8) } + } +} diff --git a/p-token/src/processor/burn_checked.rs b/p-token/src/processor/burn_checked.rs new file mode 100644 index 0000000..5ada832 --- /dev/null +++ b/p-token/src/processor/burn_checked.rs @@ -0,0 +1,47 @@ +use std::marker::PhantomData; + +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; + +use super::burn::process_burn; + +#[inline(always)] +pub fn process_burn_checked( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + decimals: u8, +) -> ProgramResult { + process_burn(program_id, accounts, amount, Some(decimals)) +} + +pub struct BurnChecked<'a> { + raw: *const u8, + + _data: PhantomData<&'a [u8]>, +} + +impl BurnChecked<'_> { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != 9 { + return Err(ProgramError::InvalidInstructionData); + } + + Ok(BurnChecked { + raw: bytes.as_ptr(), + _data: PhantomData, + }) + } + + pub fn amount(&self) -> u64 { + unsafe { + let amount = self.raw as *const u64; + amount.read_unaligned() + } + } + + pub fn decimals(&self) -> u8 { + unsafe { *self.raw.add(8) } + } +} diff --git a/p-token/src/processor/initialize_account2.rs b/p-token/src/processor/initialize_account2.rs new file mode 100644 index 0000000..476fb89 --- /dev/null +++ b/p-token/src/processor/initialize_account2.rs @@ -0,0 +1,12 @@ +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; + +use super::initialize_account::process_initialize_account; + +#[inline(always)] +pub fn process_initialize_account2( + program_id: &Pubkey, + accounts: &[AccountInfo], + owner: &Pubkey, +) -> ProgramResult { + process_initialize_account(program_id, accounts, Some(owner), true) +} diff --git a/p-token/src/processor/initialize_account3.rs b/p-token/src/processor/initialize_account3.rs new file mode 100644 index 0000000..d375ef1 --- /dev/null +++ b/p-token/src/processor/initialize_account3.rs @@ -0,0 +1,12 @@ +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; + +use super::initialize_account::process_initialize_account; + +#[inline(always)] +pub fn process_initialize_account3( + program_id: &Pubkey, + accounts: &[AccountInfo], + owner: &Pubkey, +) -> ProgramResult { + process_initialize_account(program_id, accounts, Some(owner), false) +} diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 180e8b5..74fd57a 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -1,12 +1,11 @@ -use bytemuck::{Pod, Zeroable}; use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, - pubkey::{Pubkey, PUBKEY_BYTES}, + pubkey::Pubkey, sysvars::{rent::Rent, Sysvar}, ProgramResult, }; -use std::mem::size_of; +use std::{marker::PhantomData, mem::size_of}; use token_interface::{ error::TokenError, state::{mint::Mint, PodCOption}, @@ -52,17 +51,18 @@ pub fn process_initialize_mint( // Initialize the mint. - mint.mint_authority = PodCOption::from(Some(args.data.mint_authority)); - mint.decimals = args.data.decimals; + mint.mint_authority = PodCOption::from(Some(*args.mint_authority())); + mint.decimals = args.decimals(); mint.is_initialized = true.into(); - if let Some(freeze_authority) = args.freeze_authority { + if let Some(freeze_authority) = args.freeze_authority() { mint.freeze_authority = PodCOption::from(Some(*freeze_authority)); } Ok(()) } +/* /// Instruction data for the `InitializeMint` instruction. pub struct InitializeMint<'a> { pub data: &'a MintData, @@ -107,3 +107,45 @@ pub struct MintData { /// The authority/multisignature to mint tokens. pub mint_authority: Pubkey, } +*/ +/// Instruction data for the `InitializeMint2` instruction. +pub struct InitializeMint<'a> { + raw: *const u8, + + _data: PhantomData<&'a [u8]>, +} + +impl InitializeMint<'_> { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + // The minimum expected size of the instruction data. + // - decimals (1 byte) + // - mint_authority (32 bytes) + // - option + freeze_authority (1 byte + 32 bytes) + if bytes.len() < 34 { + return Err(ProgramError::InvalidInstructionData); + } + + Ok(InitializeMint { + raw: bytes.as_ptr(), + _data: PhantomData, + }) + } + + pub fn decimals(&self) -> u8 { + unsafe { *self.raw } + } + + pub fn mint_authority(&self) -> &Pubkey { + unsafe { &*(self.raw.add(1) as *const Pubkey) } + } + + pub fn freeze_authority(&self) -> Option<&Pubkey> { + unsafe { + if *self.raw.add(33) == 0 { + Option::None + } else { + Option::Some(&*(self.raw.add(34) as *const Pubkey)) + } + } + } +} diff --git a/p-token/src/processor/initialize_mint2.rs b/p-token/src/processor/initialize_mint2.rs new file mode 100644 index 0000000..0f5a8a2 --- /dev/null +++ b/p-token/src/processor/initialize_mint2.rs @@ -0,0 +1,7 @@ +use pinocchio::{account_info::AccountInfo, ProgramResult}; + +use super::initialize_mint::{process_initialize_mint, InitializeMint}; + +pub fn process_initialize_mint2(accounts: &[AccountInfo], args: &InitializeMint) -> ProgramResult { + process_initialize_mint(accounts, args, false) +} diff --git a/p-token/src/processor/initialize_multisig2.rs b/p-token/src/processor/initialize_multisig2.rs new file mode 100644 index 0000000..7ca4a6f --- /dev/null +++ b/p-token/src/processor/initialize_multisig2.rs @@ -0,0 +1,7 @@ +use pinocchio::{account_info::AccountInfo, ProgramResult}; + +use super::initialize_multisig::process_initialize_multisig; + +pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { + process_initialize_multisig(accounts, m, false) +} diff --git a/p-token/src/processor/mint_to_checked.rs b/p-token/src/processor/mint_to_checked.rs new file mode 100644 index 0000000..98e37da --- /dev/null +++ b/p-token/src/processor/mint_to_checked.rs @@ -0,0 +1,47 @@ +use std::marker::PhantomData; + +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; + +use super::mint_to::process_mint_to; + +#[inline(always)] +pub fn process_mint_to_checked( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + decimals: u8, +) -> ProgramResult { + process_mint_to(program_id, accounts, amount, Some(decimals)) +} + +pub struct MintToChecked<'a> { + raw: *const u8, + + _data: PhantomData<&'a [u8]>, +} + +impl MintToChecked<'_> { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != 9 { + return Err(ProgramError::InvalidInstructionData); + } + + Ok(MintToChecked { + raw: bytes.as_ptr(), + _data: PhantomData, + }) + } + + pub fn amount(&self) -> u64 { + unsafe { + let amount = self.raw as *const u64; + amount.read_unaligned() + } + } + + pub fn decimals(&self) -> u8 { + unsafe { *self.raw.add(8) } + } +} diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index c3ef040..4714b76 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -7,17 +7,25 @@ use token_interface::{ }; pub mod approve; +pub mod approve_checked; pub mod burn; +pub mod burn_checked; pub mod close_account; pub mod freeze_account; pub mod initialize_account; +pub mod initialize_account2; +pub mod initialize_account3; pub mod initialize_mint; +pub mod initialize_mint2; pub mod initialize_multisig; +pub mod initialize_multisig2; pub mod mint_to; +pub mod mint_to_checked; pub mod revoke; pub mod set_authority; pub mod thaw_account; pub mod transfer; +pub mod transfer_checked; // Private processor to toggle the account state. This logic is reused by the // freeze and thaw account instructions. mod toggle_account_state; diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs index e4a6702..92db0cc 100644 --- a/p-token/src/processor/transfer.rs +++ b/p-token/src/processor/transfer.rs @@ -54,13 +54,15 @@ pub fn process_transfer( // Validates source and destination accounts. - let source_account_data = unsafe { source_account_info.borrow_mut_data_unchecked() }; - let source_account = bytemuck::try_from_bytes_mut::(source_account_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let source_account = bytemuck::try_from_bytes_mut::(unsafe { + source_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; - let destination_account_data = unsafe { destination_account_info.borrow_mut_data_unchecked() }; - let destination_account = bytemuck::try_from_bytes_mut::(destination_account_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let destination_account = bytemuck::try_from_bytes_mut::(unsafe { + destination_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; if source_account.is_frozen() || destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -84,8 +86,9 @@ pub fn process_transfer( return Err(TokenError::MintMismatch.into()); } - let mint_data = mint_info.try_borrow_data()?; - let mint = bytemuck::from_bytes::(&mint_data); + let mint = + bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; if decimals != mint.decimals { return Err(TokenError::MintDecimalsMismatch.into()); diff --git a/p-token/src/processor/transfer_checked.rs b/p-token/src/processor/transfer_checked.rs new file mode 100644 index 0000000..60f4cda --- /dev/null +++ b/p-token/src/processor/transfer_checked.rs @@ -0,0 +1,47 @@ +use std::marker::PhantomData; + +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; + +use super::transfer::process_transfer; + +#[inline(always)] +pub fn process_transfer_checked( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + decimals: u8, +) -> ProgramResult { + process_transfer(program_id, accounts, amount, Some(decimals)) +} + +pub struct TransferChecked<'a> { + raw: *const u8, + + _data: PhantomData<&'a [u8]>, +} + +impl TransferChecked<'_> { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != 9 { + return Err(ProgramError::InvalidInstructionData); + } + + Ok(TransferChecked { + raw: bytes.as_ptr(), + _data: PhantomData, + }) + } + + pub fn amount(&self) -> u64 { + unsafe { + let amount = self.raw as *const u64; + amount.read_unaligned() + } + } + + pub fn decimals(&self) -> u8 { + unsafe { *self.raw.add(8) } + } +} diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs new file mode 100644 index 0000000..63b3ad7 --- /dev/null +++ b/p-token/tests/approve_checked.rs @@ -0,0 +1,91 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn approve_checked(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account with 100 tokens. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + mint::mint( + &mut context, + &mint, + &account, + &mint_authority, + 100, + &token_program, + ) + .await + .unwrap(); + + // When we approve a delegate. + + let delegate = Pubkey::new_unique(); + + let mut approve_ix = spl_token::instruction::approve_checked( + &spl_token::ID, + &account, + &mint, + &delegate, + &owner.pubkey(), + &[], + 50, + 0, + ) + .unwrap(); + approve_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[approve_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the account should have the delegate and delegated amount. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.delegate.is_some()); + assert!(account.delegate.unwrap() == delegate); + assert!(account.delegated_amount == 50); +} diff --git a/p-token/tests/burn_checked.rs b/p-token/tests/burn_checked.rs new file mode 100644 index 0000000..0502653 --- /dev/null +++ b/p-token/tests/burn_checked.rs @@ -0,0 +1,86 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn burn_checked(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account with 100 tokens. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + mint::mint( + &mut context, + &mint, + &account, + &mint_authority, + 100, + &token_program, + ) + .await + .unwrap(); + + // When we burn 50 tokens. + + let mut burn_ix = spl_token::instruction::burn_checked( + &spl_token::ID, + &account, + &mint, + &owner.pubkey(), + &[], + 50, + 0, + ) + .unwrap(); + burn_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[burn_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the account should have 50 tokens remaining. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.amount == 50); +} diff --git a/p-token/tests/initialize_account2.rs b/p-token/tests/initialize_account2.rs new file mode 100644 index 0000000..8eff530 --- /dev/null +++ b/p-token/tests/initialize_account2.rs @@ -0,0 +1,93 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::mint; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn initialize_account2(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority, + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // Given a mint authority, freeze authority and an account keypair. + + let owner = Pubkey::new_unique(); + let account = Keypair::new(); + + let account_size = 165; + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_account2( + &spl_token::ID, + &account.pubkey(), + &mint, + &owner, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new mint account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size), + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(!account.is_frozen()); + assert!(account.owner == owner); + assert!(account.mint == mint); +} diff --git a/p-token/tests/initialize_account3.rs b/p-token/tests/initialize_account3.rs new file mode 100644 index 0000000..795c42a --- /dev/null +++ b/p-token/tests/initialize_account3.rs @@ -0,0 +1,93 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::mint; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn initialize_account3(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority, + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // Given a mint authority, freeze authority and an account keypair. + + let owner = Pubkey::new_unique(); + let account = Keypair::new(); + + let account_size = 165; + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_account3( + &spl_token::ID, + &account.pubkey(), + &mint, + &owner, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new mint account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size), + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(!account.is_frozen()); + assert!(account.owner == owner); + assert!(account.mint == mint); +} diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs new file mode 100644 index 0000000..e5bf6e3 --- /dev/null +++ b/p-token/tests/initialize_mint2.rs @@ -0,0 +1,83 @@ +#![cfg(feature = "test-sbf")] + +use std::mem::size_of; + +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_option::COption, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; +use token_interface::state::mint::Mint; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn initialize_mint2(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint authority, freeze authority and an account keypair. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + let account = Keypair::new(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_mint2( + &spl_token::ID, + &account.pubkey(), + &mint_authority, + Some(&freeze_authority), + 0, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new mint account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size), + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let mint = spl_token::state::Mint::unpack(&account.data).unwrap(); + + assert!(mint.is_initialized); + assert!(mint.mint_authority == COption::Some(mint_authority)); + assert!(mint.freeze_authority == COption::Some(freeze_authority)); + assert!(mint.decimals == 0) +} diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs new file mode 100644 index 0000000..f8427b5 --- /dev/null +++ b/p-token/tests/initialize_multisig2.rs @@ -0,0 +1,79 @@ +#![cfg(feature = "test-sbf")] + +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; +use spl_token::state::Multisig; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn initialize_multisig2(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given an account + + let multisig = Keypair::new(); + let signer1 = Pubkey::new_unique(); + let signer2 = Pubkey::new_unique(); + let signer3 = Pubkey::new_unique(); + let signers = vec![&signer1, &signer2, &signer3]; + + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_multisig2( + &spl_token::ID, + &multisig.pubkey(), + &signers, + 2, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new multisig account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &multisig.pubkey(), + rent.minimum_balance(Multisig::LEN), + Multisig::LEN as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &multisig], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the multisig has the correct data. + + let account = context + .banks_client + .get_account(multisig.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let multisig = spl_token::state::Multisig::unpack(&account.data).unwrap(); + + assert!(multisig.is_initialized); + assert_eq!(multisig.n, 3); + assert_eq!(multisig.m, 2); +} diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs new file mode 100644 index 0000000..42fcb8f --- /dev/null +++ b/p-token/tests/mint_to_checked.rs @@ -0,0 +1,76 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn mint_to_checked(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + // When we mint tokens to it. + + let mut mint_ix = spl_token::instruction::mint_to_checked( + &spl_token::ID, + &mint, + &account, + &mint_authority.pubkey(), + &[], + 100, + 0, + ) + .unwrap(); + // Switches the program id to the token program. + mint_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[mint_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &mint_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.amount == 100); +} diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs new file mode 100644 index 0000000..9616d22 --- /dev/null +++ b/p-token/tests/transfer_checked.rs @@ -0,0 +1,92 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::{account, mint}; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, +}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn transfer_checked(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority.pubkey(), + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // And a token account with 100 tokens. + + let owner = Keypair::new(); + + let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + + mint::mint( + &mut context, + &mint, + &account, + &mint_authority, + 100, + &token_program, + ) + .await + .unwrap(); + + // When we transfer the tokens. + + let destination = Pubkey::new_unique(); + + let destination_account = + account::initialize(&mut context, &mint, &destination, &token_program).await; + + let mut transfer_ix = spl_token::instruction::transfer_checked( + &spl_token::ID, + &account, + &mint, + &destination_account, + &owner.pubkey(), + &[], + 100, + 0, + ) + .unwrap(); + transfer_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[transfer_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then an account has the correct data. + + let account = context.banks_client.get_account(account).await.unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Account::unpack(&account.data).unwrap(); + + assert!(account.amount == 0); +} From d53af68c89c0a99264e944712b01d31402c8b001 Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 21 Nov 2024 00:16:25 +0000 Subject: [PATCH 275/335] Inline tweaks --- p-token/src/processor/freeze_account.rs | 1 + p-token/src/processor/initialize_mint2.rs | 1 + p-token/src/processor/initialize_multisig2.rs | 1 + p-token/src/processor/thaw_account.rs | 1 + p-token/src/processor/toggle_account_state.rs | 1 - 5 files changed, 4 insertions(+), 1 deletion(-) diff --git a/p-token/src/processor/freeze_account.rs b/p-token/src/processor/freeze_account.rs index e8cb7b5..188a019 100644 --- a/p-token/src/processor/freeze_account.rs +++ b/p-token/src/processor/freeze_account.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::toggle_account_state::process_toggle_account_state; +#[inline(always)] pub fn process_freeze_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { process_toggle_account_state(program_id, accounts, true) } diff --git a/p-token/src/processor/initialize_mint2.rs b/p-token/src/processor/initialize_mint2.rs index 0f5a8a2..7693ef5 100644 --- a/p-token/src/processor/initialize_mint2.rs +++ b/p-token/src/processor/initialize_mint2.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; use super::initialize_mint::{process_initialize_mint, InitializeMint}; +#[inline(always)] pub fn process_initialize_mint2(accounts: &[AccountInfo], args: &InitializeMint) -> ProgramResult { process_initialize_mint(accounts, args, false) } diff --git a/p-token/src/processor/initialize_multisig2.rs b/p-token/src/processor/initialize_multisig2.rs index 7ca4a6f..eba10b1 100644 --- a/p-token/src/processor/initialize_multisig2.rs +++ b/p-token/src/processor/initialize_multisig2.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; use super::initialize_multisig::process_initialize_multisig; +#[inline(always)] pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { process_initialize_multisig(accounts, m, false) } diff --git a/p-token/src/processor/thaw_account.rs b/p-token/src/processor/thaw_account.rs index b432877..a7f4da0 100644 --- a/p-token/src/processor/thaw_account.rs +++ b/p-token/src/processor/thaw_account.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::toggle_account_state::process_toggle_account_state; +#[inline(always)] pub fn process_thaw_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { process_toggle_account_state(program_id, accounts, false) } diff --git a/p-token/src/processor/toggle_account_state.rs b/p-token/src/processor/toggle_account_state.rs index aaac762..69fbac0 100644 --- a/p-token/src/processor/toggle_account_state.rs +++ b/p-token/src/processor/toggle_account_state.rs @@ -11,7 +11,6 @@ use token_interface::{ use super::validate_owner; -#[inline(always)] pub fn process_toggle_account_state( program_id: &Pubkey, accounts: &[AccountInfo], From bb48b87cb19bedcd26313a39b6c6ce26081476bc Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 21 Nov 2024 02:24:48 +0000 Subject: [PATCH 276/335] instruction: SyncNative --- p-token/src/entrypoint.rs | 8 +++++++ p-token/src/processor/mod.rs | 1 + p-token/src/processor/sync_native.rs | 35 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 p-token/src/processor/sync_native.rs diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 0f6224a..306c65f 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -21,6 +21,7 @@ use crate::processor::{ mint_to_checked::{process_mint_to_checked, MintToChecked}, revoke::process_revoke, set_authority::{process_set_authority, SetAuthority}, + sync_native::process_sync_native, thaw_account::process_thaw_account, transfer::process_transfer, transfer_checked::{process_transfer_checked, TransferChecked}, @@ -194,6 +195,13 @@ pub fn process_instruction( process_initialize_account2(program_id, accounts, owner) } + // 17 - SyncNative + Some((&17, _)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: SyncNative"); + + process_sync_native(program_id, accounts) + } // 18 - InitializeAccount3 Some((&18, data)) => { #[cfg(feature = "logging")] diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 4714b76..214eb69 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -23,6 +23,7 @@ pub mod mint_to; pub mod mint_to_checked; pub mod revoke; pub mod set_authority; +pub mod sync_native; pub mod thaw_account; pub mod transfer; pub mod transfer_checked; diff --git a/p-token/src/processor/sync_native.rs b/p-token/src/processor/sync_native.rs new file mode 100644 index 0000000..8fef93d --- /dev/null +++ b/p-token/src/processor/sync_native.rs @@ -0,0 +1,35 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{error::TokenError, state::account::Account}; + +use super::check_account_owner; + +pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + let [native_account_info, _remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + check_account_owner(program_id, native_account_info)?; + + let native_account = bytemuck::try_from_bytes_mut::(unsafe { + native_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if let Option::Some(rent_exempt_reserve) = native_account.is_native.get() { + let new_amount = native_account_info + .lamports() + .checked_sub(u64::from(rent_exempt_reserve)) + .ok_or(TokenError::Overflow)?; + + if new_amount < native_account.amount.into() { + return Err(TokenError::InvalidState.into()); + } + native_account.amount = new_amount.into(); + } else { + return Err(TokenError::NonNativeNotSupported.into()); + } + + Ok(()) +} From 144bcfa27c51b21a71d6ffa5e5760eb7efe35d37 Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 21 Nov 2024 12:44:16 +0000 Subject: [PATCH 277/335] Add remaining instructions --- p-token/src/entrypoint.rs | 42 ++++++++++++++ p-token/src/processor/amount_to_ui_amount.rs | 25 ++++++++ .../src/processor/get_account_data_size.rs | 25 ++++++++ .../processor/initialize_immutable_owner.rs | 17 ++++++ p-token/src/processor/mod.rs | 58 +++++++++++++++++++ p-token/src/processor/sync_native.rs | 4 +- p-token/src/processor/ui_amount_to_amount.rs | 25 ++++++++ 7 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 p-token/src/processor/amount_to_ui_amount.rs create mode 100644 p-token/src/processor/get_account_data_size.rs create mode 100644 p-token/src/processor/initialize_immutable_owner.rs create mode 100644 p-token/src/processor/ui_amount_to_amount.rs diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 306c65f..edcd6b4 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -1,18 +1,23 @@ +use core::str; + use pinocchio::{ account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; use crate::processor::{ + amount_to_ui_amount::process_amount_to_ui_amount, approve::process_approve, approve_checked::{process_approve_checked, ApproveChecked}, burn::process_burn, burn_checked::{process_burn_checked, BurnChecked}, close_account::process_close_account, freeze_account::process_freeze_account, + get_account_data_size::process_get_account_data_size, initialize_account::process_initialize_account, initialize_account2::process_initialize_account2, initialize_account3::process_initialize_account3, + initialize_immutable_owner::process_initialize_immutable_owner, initialize_mint::{process_initialize_mint, InitializeMint}, initialize_mint2::process_initialize_mint2, initialize_multisig::process_initialize_multisig, @@ -25,6 +30,7 @@ use crate::processor::{ thaw_account::process_thaw_account, transfer::process_transfer, transfer_checked::{process_transfer_checked, TransferChecked}, + ui_amount_to_amount::process_ui_amount_to_amount, }; entrypoint!(process_instruction); @@ -229,6 +235,42 @@ pub fn process_instruction( process_initialize_mint2(accounts, &instruction) } + // 21 - GetAccountDataSize + Some((&21, _)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: GetAccountDataSize"); + + process_get_account_data_size(program_id, accounts) + } + // 22 - InitializeImmutableOwner + Some((&22, _)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeImmutableOwner"); + + process_initialize_immutable_owner(accounts) + } + // 23 - AmountToUiAmount + Some((&23, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: AmountToUiAmount"); + + let amount = u64::from_le_bytes( + data.try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + process_amount_to_ui_amount(program_id, accounts, amount) + } + // 24 - UiAmountToAmount + Some((&24, data)) => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: UiAmountToAmount"); + + let ui_amount = + str::from_utf8(data).map_err(|_error| ProgramError::InvalidInstructionData)?; + + process_ui_amount_to_amount(program_id, accounts, ui_amount) + } _ => Err(ProgramError::InvalidInstructionData), } } diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs new file mode 100644 index 0000000..4f661d2 --- /dev/null +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -0,0 +1,25 @@ +use pinocchio::{ + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, + pubkey::Pubkey, ProgramResult, +}; +use token_interface::{error::TokenError, state::mint::Mint}; + +use super::{amount_to_ui_amount_string_trimmed, check_account_owner}; + +pub fn process_amount_to_ui_amount( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, +) -> ProgramResult { + let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; + check_account_owner(program_id, mint_info)?; + + let mint = + bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) + .map_err(|_error| TokenError::InvalidMint)?; + + let ui_amount = amount_to_ui_amount_string_trimmed(amount, mint.decimals); + set_return_data(&ui_amount.into_bytes()); + + Ok(()) +} diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs new file mode 100644 index 0000000..a886914 --- /dev/null +++ b/p-token/src/processor/get_account_data_size.rs @@ -0,0 +1,25 @@ +use pinocchio::{ + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, + pubkey::Pubkey, ProgramResult, +}; +use token_interface::state::{account::Account, mint::Mint}; + +use super::check_account_owner; + +pub fn process_get_account_data_size( + program_id: &Pubkey, + accounts: &[AccountInfo], +) -> ProgramResult { + let [mint_info, _remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + check_account_owner(program_id, mint_info)?; + + let _ = bytemuck::try_from_bytes::(unsafe { mint_info.borrow_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + set_return_data(&Account::LEN.to_le_bytes()); + + Ok(()) +} diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs new file mode 100644 index 0000000..579c2ce --- /dev/null +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -0,0 +1,17 @@ +use pinocchio::{account_info::AccountInfo, msg, program_error::ProgramError, ProgramResult}; +use token_interface::{error::TokenError, state::account::Account}; + +pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { + let token_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; + + let account = bytemuck::try_from_bytes_mut::(unsafe { + token_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if account.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } + msg!("Please upgrade to SPL Token 2022 for immutable owner support"); + Ok(()) +} diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 214eb69..6e51486 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -6,15 +6,18 @@ use token_interface::{ state::multisig::{Multisig, MAX_SIGNERS}, }; +pub mod amount_to_ui_amount; pub mod approve; pub mod approve_checked; pub mod burn; pub mod burn_checked; pub mod close_account; pub mod freeze_account; +pub mod get_account_data_size; pub mod initialize_account; pub mod initialize_account2; pub mod initialize_account3; +pub mod initialize_immutable_owner; pub mod initialize_mint; pub mod initialize_mint2; pub mod initialize_multisig; @@ -27,6 +30,7 @@ pub mod sync_native; pub mod thaw_account; pub mod transfer; pub mod transfer_checked; +pub mod ui_amount_to_amount; // Private processor to toggle the account state. This logic is reused by the // freeze and thaw account instructions. mod toggle_account_state; @@ -92,3 +96,57 @@ pub fn validate_owner( Ok(()) } + +/// Convert a raw amount to its UI representation using the given decimals field +/// Excess zeroes or unneeded decimal point are trimmed. +#[inline(always)] +pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { + let mut s = amount_to_ui_amount_string(amount, decimals); + if decimals > 0 { + let zeros_trimmed = s.trim_end_matches('0'); + s = zeros_trimmed.trim_end_matches('.').to_string(); + } + s +} + +/// Convert a raw amount to its UI representation (using the decimals field +/// defined in its mint) +#[inline(always)] +pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { + let decimals = decimals as usize; + if decimals > 0 { + // Left-pad zeros to decimals + 1, so we at least have an integer zero + let mut s = format!("{:01$}", amount, decimals + 1); + // Add the decimal point (Sorry, "," locales!) + s.insert(s.len() - decimals, '.'); + s + } else { + amount.to_string() + } +} + +/// Try to convert a UI representation of a token amount to its raw amount using +/// the given decimals field +pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { + let decimals = decimals as usize; + let mut parts = ui_amount.split('.'); + // splitting a string, even an empty one, will always yield an iterator of at + // least length == 1 + let mut amount_str = parts.next().unwrap().to_string(); + let after_decimal = parts.next().unwrap_or(""); + let after_decimal = after_decimal.trim_end_matches('0'); + if (amount_str.is_empty() && after_decimal.is_empty()) + || parts.next().is_some() + || after_decimal.len() > decimals + { + return Err(ProgramError::InvalidArgument); + } + + amount_str.push_str(after_decimal); + for _ in 0..decimals.saturating_sub(after_decimal.len()) { + amount_str.push('0'); + } + amount_str + .parse::() + .map_err(|_| ProgramError::InvalidArgument) +} diff --git a/p-token/src/processor/sync_native.rs b/p-token/src/processor/sync_native.rs index 8fef93d..abbe161 100644 --- a/p-token/src/processor/sync_native.rs +++ b/p-token/src/processor/sync_native.rs @@ -6,9 +6,7 @@ use token_interface::{error::TokenError, state::account::Account}; use super::check_account_owner; pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - let [native_account_info, _remaning @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; + let native_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(program_id, native_account_info)?; diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs new file mode 100644 index 0000000..b2382a2 --- /dev/null +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -0,0 +1,25 @@ +use pinocchio::{ + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, + pubkey::Pubkey, ProgramResult, +}; +use token_interface::{error::TokenError, state::mint::Mint}; + +use super::{check_account_owner, try_ui_amount_into_amount}; + +pub fn process_ui_amount_to_amount( + program_id: &Pubkey, + accounts: &[AccountInfo], + ui_amount: &str, +) -> ProgramResult { + let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; + check_account_owner(program_id, mint_info)?; + + let mint = + bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) + .map_err(|_error| TokenError::InvalidMint)?; + + let amount = try_ui_amount_into_amount(ui_amount.to_string(), mint.decimals)?; + set_return_data(&amount.to_le_bytes()); + + Ok(()) +} From e5791478915a0708b8b66ad04f6f3d7fb6137e29 Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 21 Nov 2024 13:36:58 +0000 Subject: [PATCH 278/335] Refactor shared processors --- p-token/src/entrypoint.rs | 15 +- p-token/src/processor/approve.rs | 68 +------- p-token/src/processor/approve_checked.rs | 4 +- p-token/src/processor/burn.rs | 90 +--------- p-token/src/processor/burn_checked.rs | 4 +- p-token/src/processor/freeze_account.rs | 3 +- p-token/src/processor/initialize_account.rs | 101 +---------- p-token/src/processor/initialize_account2.rs | 4 +- p-token/src/processor/initialize_account3.rs | 4 +- p-token/src/processor/initialize_mint.rs | 152 +--------------- p-token/src/processor/initialize_mint2.rs | 4 +- p-token/src/processor/initialize_multisig2.rs | 4 +- p-token/src/processor/mint_to.rs | 66 +------ p-token/src/processor/mint_to_checked.rs | 4 +- p-token/src/processor/mod.rs | 5 +- p-token/src/processor/shared/approve.rs | 74 ++++++++ p-token/src/processor/shared/burn.rs | 91 ++++++++++ .../processor/shared/initialize_account.rs | 101 +++++++++++ .../src/processor/shared/initialize_mint.rs | 106 ++++++++++++ .../processor/shared/initialize_multisig.rs | 64 +++++++ p-token/src/processor/shared/mint_to.rs | 72 ++++++++ p-token/src/processor/shared/mod.rs | 8 + .../{ => shared}/toggle_account_state.rs | 3 +- p-token/src/processor/shared/transfer.rs | 162 ++++++++++++++++++ p-token/src/processor/thaw_account.rs | 3 +- p-token/src/processor/transfer.rs | 156 +---------------- p-token/src/processor/transfer_checked.rs | 4 +- 27 files changed, 729 insertions(+), 643 deletions(-) create mode 100644 p-token/src/processor/shared/approve.rs create mode 100644 p-token/src/processor/shared/burn.rs create mode 100644 p-token/src/processor/shared/initialize_account.rs create mode 100644 p-token/src/processor/shared/initialize_mint.rs create mode 100644 p-token/src/processor/shared/initialize_multisig.rs create mode 100644 p-token/src/processor/shared/mint_to.rs create mode 100644 p-token/src/processor/shared/mod.rs rename p-token/src/processor/{ => shared}/toggle_account_state.rs (96%) create mode 100644 p-token/src/processor/shared/transfer.rs diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index edcd6b4..bdbee3f 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -18,7 +18,7 @@ use crate::processor::{ initialize_account2::process_initialize_account2, initialize_account3::process_initialize_account3, initialize_immutable_owner::process_initialize_immutable_owner, - initialize_mint::{process_initialize_mint, InitializeMint}, + initialize_mint::process_initialize_mint, initialize_mint2::process_initialize_mint2, initialize_multisig::process_initialize_multisig, initialize_multisig2::process_initialize_multisig2, @@ -26,6 +26,7 @@ use crate::processor::{ mint_to_checked::{process_mint_to_checked, MintToChecked}, revoke::process_revoke, set_authority::{process_set_authority, SetAuthority}, + shared::initialize_mint::InitializeMint, sync_native::process_sync_native, thaw_account::process_thaw_account, transfer::process_transfer, @@ -49,14 +50,14 @@ pub fn process_instruction( let instruction = InitializeMint::try_from_bytes(data)?; - process_initialize_mint(accounts, &instruction, true) + process_initialize_mint(accounts, &instruction) } // 1 - InitializeAccount Some((&1, _)) => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeAccount"); - process_initialize_account(program_id, accounts, None, true) + process_initialize_account(program_id, accounts) } // 2 - InitializeMultisig Some((&2, data)) => { @@ -77,7 +78,7 @@ pub fn process_instruction( .map_err(|_error| ProgramError::InvalidInstructionData)?, ); - process_transfer(program_id, accounts, amount, None) + process_transfer(program_id, accounts, amount) } // 4 - Approve Some((&4, data)) => { @@ -89,7 +90,7 @@ pub fn process_instruction( .map_err(|_error| ProgramError::InvalidInstructionData)?, ); - process_approve(program_id, accounts, amount, None) + process_approve(program_id, accounts, amount) } // 5 - Revoke Some((&5, _)) => { @@ -121,7 +122,7 @@ pub fn process_instruction( .map_err(|_error| ProgramError::InvalidInstructionData)?, ); - process_mint_to(program_id, accounts, amount, None) + process_mint_to(program_id, accounts, amount) } // 8 - Burn Some((&8, data)) => { @@ -133,7 +134,7 @@ pub fn process_instruction( .map_err(|_error| ProgramError::InvalidInstructionData)?, ); - process_burn(program_id, accounts, amount, None) + process_burn(program_id, accounts, amount) } // 9 - CloseAccount Some((&9, _)) => { diff --git a/p-token/src/processor/approve.rs b/p-token/src/processor/approve.rs index ca09471..6a6d1cd 100644 --- a/p-token/src/processor/approve.rs +++ b/p-token/src/processor/approve.rs @@ -1,73 +1,11 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; -use token_interface::{ - error::TokenError, - state::{account::Account, mint::Mint, PodCOption}, -}; +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::validate_owner; +use super::shared; pub fn process_approve( program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, - expected_decimals: Option, ) -> ProgramResult { - let (source_account_info, expected_mint_info, delegate_info, owner_info, remaining) = - if let Some(expected_decimals) = expected_decimals { - let [source_account_info, expected_mint_info, delegate_info, owner_info, remaning @ ..] = - accounts - else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - - ( - source_account_info, - Some((expected_mint_info, expected_decimals)), - delegate_info, - owner_info, - remaning, - ) - } else { - let [source_account_info, delegate_info, owner_info, remaning @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - ( - source_account_info, - None, - delegate_info, - owner_info, - remaning, - ) - }; - - let source_account = bytemuck::try_from_bytes_mut::(unsafe { - source_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if let Some((mint_info, expected_decimals)) = expected_mint_info { - if mint_info.key() != &source_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - let mint = bytemuck::try_from_bytes::(unsafe { mint_info.borrow_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - validate_owner(program_id, &source_account.owner, owner_info, remaining)?; - - source_account.delegate = PodCOption::some(*delegate_info.key()); - source_account.delegated_amount = amount.into(); - - Ok(()) + shared::approve::process_approve(program_id, accounts, amount, None) } diff --git a/p-token/src/processor/approve_checked.rs b/p-token/src/processor/approve_checked.rs index 8ce145b..6495712 100644 --- a/p-token/src/processor/approve_checked.rs +++ b/p-token/src/processor/approve_checked.rs @@ -4,7 +4,7 @@ use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use super::approve::process_approve; +use super::shared; #[inline(always)] pub fn process_approve_checked( @@ -13,7 +13,7 @@ pub fn process_approve_checked( amount: u64, decimals: u8, ) -> ProgramResult { - process_approve(program_id, accounts, amount, Some(decimals)) + shared::approve::process_approve(program_id, accounts, amount, Some(decimals)) } pub struct ApproveChecked<'a> { diff --git a/p-token/src/processor/burn.rs b/p-token/src/processor/burn.rs index f0a1c54..34aa606 100644 --- a/p-token/src/processor/burn.rs +++ b/p-token/src/processor/burn.rs @@ -1,89 +1,7 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; -use token_interface::{ - error::TokenError, - state::{account::Account, mint::Mint}, -}; +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::{check_account_owner, is_owned_by_system_program_or_incinerator, validate_owner}; +use super::shared; -/// Processes a [Burn](enum.TokenInstruction.html) instruction. -pub fn process_burn( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - expected_decimals: Option, -) -> ProgramResult { - let [source_account_info, mint_info, authority_info, remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - - // Safety: There are no conflicting borrows – the source account is only borrowed once. - let source_account = bytemuck::try_from_bytes_mut::(unsafe { - source_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if source_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - if source_account.is_native.is_some() { - return Err(TokenError::NativeNotSupported.into()); - } - - // Ensure the source account has the sufficient amount. This is done before - // the value is updated on the account. - let updated_source_amount = u64::from(source_account.amount) - .checked_sub(amount) - .ok_or(TokenError::InsufficientFunds)?; - - // Safety: There are no conflicting borrows – the mint account is only borrowed once. - let mint = - bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if mint_info.key() != &source_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - if !is_owned_by_system_program_or_incinerator(&source_account.owner) { - match source_account.delegate.as_ref() { - Some(delegate) if authority_info.key() == delegate => { - validate_owner(program_id, delegate, authority_info, remaining)?; - - let delegated_amount = u64::from(source_account.delegated_amount) - .checked_sub(amount) - .ok_or(TokenError::InsufficientFunds)?; - source_account.delegated_amount = delegated_amount.into(); - - if delegated_amount == 0 { - source_account.delegate.clear(); - } - } - _ => { - validate_owner(program_id, &source_account.owner, authority_info, remaining)?; - } - } - } - - if amount == 0 { - check_account_owner(program_id, source_account_info)?; - check_account_owner(program_id, mint_info)?; - } - - source_account.amount = updated_source_amount.into(); - - let mint_supply = u64::from(mint.supply) - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - mint.supply = mint_supply.into(); - - Ok(()) +pub fn process_burn(program_id: &Pubkey, accounts: &[AccountInfo], amount: u64) -> ProgramResult { + shared::burn::process_burn(program_id, accounts, amount, None) } diff --git a/p-token/src/processor/burn_checked.rs b/p-token/src/processor/burn_checked.rs index 5ada832..aac4d6d 100644 --- a/p-token/src/processor/burn_checked.rs +++ b/p-token/src/processor/burn_checked.rs @@ -4,7 +4,7 @@ use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use super::burn::process_burn; +use super::shared; #[inline(always)] pub fn process_burn_checked( @@ -13,7 +13,7 @@ pub fn process_burn_checked( amount: u64, decimals: u8, ) -> ProgramResult { - process_burn(program_id, accounts, amount, Some(decimals)) + shared::burn::process_burn(program_id, accounts, amount, Some(decimals)) } pub struct BurnChecked<'a> { diff --git a/p-token/src/processor/freeze_account.rs b/p-token/src/processor/freeze_account.rs index 188a019..910f9ee 100644 --- a/p-token/src/processor/freeze_account.rs +++ b/p-token/src/processor/freeze_account.rs @@ -1,8 +1,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::toggle_account_state::process_toggle_account_state; +use super::shared::toggle_account_state::process_toggle_account_state; -#[inline(always)] pub fn process_freeze_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { process_toggle_account_state(program_id, accounts, true) } diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs index ac8efa9..fd2dab8 100644 --- a/p-token/src/processor/initialize_account.rs +++ b/p-token/src/processor/initialize_account.rs @@ -1,100 +1,7 @@ -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::Pubkey, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, -}; -use std::mem::size_of; -use token_interface::{ - error::TokenError, - native_mint::is_native_mint, - state::{ - account::{Account, AccountState}, - mint::Mint, - PodCOption, - }, -}; +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::check_account_owner; +use super::shared; -pub fn process_initialize_account( - program_id: &Pubkey, - accounts: &[AccountInfo], - owner: Option<&Pubkey>, - rent_sysvar_account: bool, -) -> ProgramResult { - let (new_account_info, mint_info, owner, remaning) = if let Some(owner) = owner { - let [new_account_info, mint_info, remaning @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (new_account_info, mint_info, owner, remaning) - } else { - let [new_account_info, mint_info, owner_info, remaning @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (new_account_info, mint_info, owner_info.key(), remaning) - }; - - // Check rent-exempt status of the token account. - - let is_exempt = if rent_sysvar_account { - let rent_sysvar_info = remaning.first().ok_or(ProgramError::NotEnoughAccountKeys)?; - let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; - rent.is_exempt(new_account_info.lamports(), size_of::()) - } else { - Rent::get()?.is_exempt(new_account_info.lamports(), size_of::()) - }; - - if !is_exempt { - return Err(TokenError::NotRentExempt.into()); - } - - let account_data = unsafe { new_account_info.borrow_mut_data_unchecked() }; - let account = bytemuck::try_from_bytes_mut::(account_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if account.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } - - let is_native_mint = is_native_mint(mint_info.key()); - - if !is_native_mint { - check_account_owner(program_id, mint_info)?; - - let mint_data = unsafe { mint_info.borrow_data_unchecked() }; - let mint = bytemuck::try_from_bytes::(mint_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if !bool::from(mint.is_initialized) { - return Err(TokenError::InvalidMint.into()); - } - } - - account.mint = *mint_info.key(); - account.owner = *owner; - account.close_authority.clear(); - account.delegate.clear(); - account.delegated_amount = 0u64.into(); - account.state = AccountState::Initialized as u8; - - if is_native_mint { - let rent = Rent::get()?; - let rent_exempt_reserve = rent.minimum_balance(size_of::()); - - account.is_native = PodCOption::from(Some(rent_exempt_reserve.into())); - unsafe { - account.amount = new_account_info - .borrow_lamports_unchecked() - .checked_sub(rent_exempt_reserve) - .ok_or(TokenError::Overflow)? - .into() - } - } else { - account.is_native.clear(); - account.amount = 0u64.into(); - }; - - Ok(()) +pub fn process_initialize_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { + shared::initialize_account::process_initialize_account(program_id, accounts, None, true) } diff --git a/p-token/src/processor/initialize_account2.rs b/p-token/src/processor/initialize_account2.rs index 476fb89..d199b32 100644 --- a/p-token/src/processor/initialize_account2.rs +++ b/p-token/src/processor/initialize_account2.rs @@ -1,6 +1,6 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::initialize_account::process_initialize_account; +use super::shared; #[inline(always)] pub fn process_initialize_account2( @@ -8,5 +8,5 @@ pub fn process_initialize_account2( accounts: &[AccountInfo], owner: &Pubkey, ) -> ProgramResult { - process_initialize_account(program_id, accounts, Some(owner), true) + shared::initialize_account::process_initialize_account(program_id, accounts, Some(owner), true) } diff --git a/p-token/src/processor/initialize_account3.rs b/p-token/src/processor/initialize_account3.rs index d375ef1..82ed1b5 100644 --- a/p-token/src/processor/initialize_account3.rs +++ b/p-token/src/processor/initialize_account3.rs @@ -1,6 +1,6 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::initialize_account::process_initialize_account; +use super::shared; #[inline(always)] pub fn process_initialize_account3( @@ -8,5 +8,5 @@ pub fn process_initialize_account3( accounts: &[AccountInfo], owner: &Pubkey, ) -> ProgramResult { - process_initialize_account(program_id, accounts, Some(owner), false) + shared::initialize_account::process_initialize_account(program_id, accounts, Some(owner), false) } diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 74fd57a..5601015 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -1,151 +1,7 @@ -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::Pubkey, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, -}; -use std::{marker::PhantomData, mem::size_of}; -use token_interface::{ - error::TokenError, - state::{mint::Mint, PodCOption}, -}; +use pinocchio::{account_info::AccountInfo, ProgramResult}; -pub fn process_initialize_mint( - accounts: &[AccountInfo], - args: &InitializeMint, - rent_sysvar_account: bool, -) -> ProgramResult { - let (mint_info, rent_sysvar_info) = if rent_sysvar_account { - let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (mint_info, Some(rent_sysvar_info)) - } else { - let [mint_info, _remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (mint_info, None) - }; +use super::shared::{self, initialize_mint::InitializeMint}; - let mint = - bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if mint.is_initialized.into() { - return Err(TokenError::AlreadyInUse.into()); - } - - // Check rent-exempt status of the mint account. - - let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { - let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; - rent.is_exempt(mint_info.lamports(), size_of::()) - } else { - Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) - }; - - if !is_exempt { - return Err(TokenError::NotRentExempt.into()); - } - - // Initialize the mint. - - mint.mint_authority = PodCOption::from(Some(*args.mint_authority())); - mint.decimals = args.decimals(); - mint.is_initialized = true.into(); - - if let Some(freeze_authority) = args.freeze_authority() { - mint.freeze_authority = PodCOption::from(Some(*freeze_authority)); - } - - Ok(()) -} - -/* -/// Instruction data for the `InitializeMint` instruction. -pub struct InitializeMint<'a> { - pub data: &'a MintData, - - /// The freeze authority/multisignature of the mint. - pub freeze_authority: Option<&'a Pubkey>, -} - -impl<'a> InitializeMint<'a> { - pub fn try_from_bytes(data: &'a [u8]) -> Result { - // We expect the data to be at least the size of the MintInput struct - // plus one byte for the freeze_authority option. - if data.len() <= size_of::() { - return Err(ProgramError::InvalidInstructionData); - } - - let (data, remaining) = data.split_at(size_of::()); - let data = bytemuck::from_bytes::(data); - - let freeze_authority = match remaining.split_first() { - Some((&0, _)) => None, - Some((&1, pubkey)) if pubkey.len() == PUBKEY_BYTES => { - Some(bytemuck::from_bytes::(pubkey)) - } - _ => return Err(ProgramError::InvalidInstructionData), - }; - - Ok(Self { - data, - freeze_authority, - }) - } -} - -/// Base information for the mint. -#[repr(C)] -#[derive(Clone, Copy, Default, Pod, Zeroable)] -pub struct MintData { - /// Number of base 10 digits to the right of the decimal place. - pub decimals: u8, - - /// The authority/multisignature to mint tokens. - pub mint_authority: Pubkey, -} -*/ -/// Instruction data for the `InitializeMint2` instruction. -pub struct InitializeMint<'a> { - raw: *const u8, - - _data: PhantomData<&'a [u8]>, -} - -impl InitializeMint<'_> { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - // The minimum expected size of the instruction data. - // - decimals (1 byte) - // - mint_authority (32 bytes) - // - option + freeze_authority (1 byte + 32 bytes) - if bytes.len() < 34 { - return Err(ProgramError::InvalidInstructionData); - } - - Ok(InitializeMint { - raw: bytes.as_ptr(), - _data: PhantomData, - }) - } - - pub fn decimals(&self) -> u8 { - unsafe { *self.raw } - } - - pub fn mint_authority(&self) -> &Pubkey { - unsafe { &*(self.raw.add(1) as *const Pubkey) } - } - - pub fn freeze_authority(&self) -> Option<&Pubkey> { - unsafe { - if *self.raw.add(33) == 0 { - Option::None - } else { - Option::Some(&*(self.raw.add(34) as *const Pubkey)) - } - } - } +pub fn process_initialize_mint(accounts: &[AccountInfo], args: &InitializeMint) -> ProgramResult { + shared::initialize_mint::process_initialize_mint(accounts, args, true) } diff --git a/p-token/src/processor/initialize_mint2.rs b/p-token/src/processor/initialize_mint2.rs index 7693ef5..663104c 100644 --- a/p-token/src/processor/initialize_mint2.rs +++ b/p-token/src/processor/initialize_mint2.rs @@ -1,8 +1,8 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; -use super::initialize_mint::{process_initialize_mint, InitializeMint}; +use super::shared::{self, initialize_mint::InitializeMint}; #[inline(always)] pub fn process_initialize_mint2(accounts: &[AccountInfo], args: &InitializeMint) -> ProgramResult { - process_initialize_mint(accounts, args, false) + shared::initialize_mint::process_initialize_mint(accounts, args, false) } diff --git a/p-token/src/processor/initialize_multisig2.rs b/p-token/src/processor/initialize_multisig2.rs index eba10b1..089d05b 100644 --- a/p-token/src/processor/initialize_multisig2.rs +++ b/p-token/src/processor/initialize_multisig2.rs @@ -1,8 +1,8 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; -use super::initialize_multisig::process_initialize_multisig; +use super::shared; #[inline(always)] pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { - process_initialize_multisig(accounts, m, false) + shared::initialize_multisig::process_initialize_multisig(accounts, m, false) } diff --git a/p-token/src/processor/mint_to.rs b/p-token/src/processor/mint_to.rs index acecc7a..eaea29b 100644 --- a/p-token/src/processor/mint_to.rs +++ b/p-token/src/processor/mint_to.rs @@ -1,71 +1,11 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; -use token_interface::{ - error::TokenError, - native_mint::is_native_mint, - state::{account::Account, mint::Mint}, -}; +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::{check_account_owner, validate_owner}; +use super::shared; pub fn process_mint_to( program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, - expected_decimals: Option, ) -> ProgramResult { - let [mint_info, destination_account_info, owner_info, remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - - // destination account - - let account_data = unsafe { destination_account_info.borrow_mut_data_unchecked() }; - let destination_account = bytemuck::try_from_bytes_mut::(account_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if destination_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - if is_native_mint(mint_info.key()) { - return Err(TokenError::NativeNotSupported.into()); - } - - if mint_info.key() != &destination_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - let mint_data = unsafe { mint_info.borrow_mut_data_unchecked() }; - let mint = bytemuck::try_from_bytes_mut::(mint_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if let Some(expected_decimals) = expected_decimals { - if expected_decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - match mint.mint_authority.get() { - Some(mint_authority) => validate_owner(program_id, &mint_authority, owner_info, remaining)?, - None => return Err(TokenError::FixedSupply.into()), - } - - if amount == 0 { - check_account_owner(program_id, mint_info)?; - check_account_owner(program_id, destination_account_info)?; - } - - let destination_amount = u64::from(destination_account.amount) - .checked_add(amount) - .ok_or(ProgramError::InvalidAccountData)?; - destination_account.amount = destination_amount.into(); - - let mint_supply = u64::from(mint.supply) - .checked_add(amount) - .ok_or(ProgramError::InvalidAccountData)?; - mint.supply = mint_supply.into(); - - Ok(()) + shared::mint_to::process_mint_to(program_id, accounts, amount, None) } diff --git a/p-token/src/processor/mint_to_checked.rs b/p-token/src/processor/mint_to_checked.rs index 98e37da..deb8d8e 100644 --- a/p-token/src/processor/mint_to_checked.rs +++ b/p-token/src/processor/mint_to_checked.rs @@ -4,7 +4,7 @@ use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use super::mint_to::process_mint_to; +use super::shared; #[inline(always)] pub fn process_mint_to_checked( @@ -13,7 +13,7 @@ pub fn process_mint_to_checked( amount: u64, decimals: u8, ) -> ProgramResult { - process_mint_to(program_id, accounts, amount, Some(decimals)) + shared::mint_to::process_mint_to(program_id, accounts, amount, Some(decimals)) } pub struct MintToChecked<'a> { diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 6e51486..9527cc7 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -31,9 +31,8 @@ pub mod thaw_account; pub mod transfer; pub mod transfer_checked; pub mod ui_amount_to_amount; -// Private processor to toggle the account state. This logic is reused by the -// freeze and thaw account instructions. -mod toggle_account_state; +// Shared processors. +pub mod shared; /// Incinerator address. const INCINERATOR_ID: Pubkey = diff --git a/p-token/src/processor/shared/approve.rs b/p-token/src/processor/shared/approve.rs new file mode 100644 index 0000000..303d943 --- /dev/null +++ b/p-token/src/processor/shared/approve.rs @@ -0,0 +1,74 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{ + error::TokenError, + state::{account::Account, mint::Mint, PodCOption}, +}; + +use crate::processor::validate_owner; + +#[inline(always)] +pub fn process_approve( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + expected_decimals: Option, +) -> ProgramResult { + let (source_account_info, expected_mint_info, delegate_info, owner_info, remaining) = + if let Some(expected_decimals) = expected_decimals { + let [source_account_info, expected_mint_info, delegate_info, owner_info, remaning @ ..] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + ( + source_account_info, + Some((expected_mint_info, expected_decimals)), + delegate_info, + owner_info, + remaning, + ) + } else { + let [source_account_info, delegate_info, owner_info, remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + ( + source_account_info, + None, + delegate_info, + owner_info, + remaning, + ) + }; + + let source_account = bytemuck::try_from_bytes_mut::(unsafe { + source_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + if let Some((mint_info, expected_decimals)) = expected_mint_info { + if mint_info.key() != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mint = bytemuck::try_from_bytes::(unsafe { mint_info.borrow_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + validate_owner(program_id, &source_account.owner, owner_info, remaining)?; + + source_account.delegate = PodCOption::some(*delegate_info.key()); + source_account.delegated_amount = amount.into(); + + Ok(()) +} diff --git a/p-token/src/processor/shared/burn.rs b/p-token/src/processor/shared/burn.rs new file mode 100644 index 0000000..c46d0e3 --- /dev/null +++ b/p-token/src/processor/shared/burn.rs @@ -0,0 +1,91 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{ + error::TokenError, + state::{account::Account, mint::Mint}, +}; + +use crate::processor::{ + check_account_owner, is_owned_by_system_program_or_incinerator, validate_owner, +}; + +#[inline(always)] +pub fn process_burn( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + expected_decimals: Option, +) -> ProgramResult { + let [source_account_info, mint_info, authority_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + // Safety: There are no conflicting borrows – the source account is only borrowed once. + let source_account = bytemuck::try_from_bytes_mut::(unsafe { + source_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + if source_account.is_native.is_some() { + return Err(TokenError::NativeNotSupported.into()); + } + + // Ensure the source account has the sufficient amount. This is done before + // the value is updated on the account. + let updated_source_amount = u64::from(source_account.amount) + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + + // Safety: There are no conflicting borrows – the mint account is only borrowed once. + let mint = + bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if mint_info.key() != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + if !is_owned_by_system_program_or_incinerator(&source_account.owner) { + match source_account.delegate.as_ref() { + Some(delegate) if authority_info.key() == delegate => { + validate_owner(program_id, delegate, authority_info, remaining)?; + + let delegated_amount = u64::from(source_account.delegated_amount) + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + source_account.delegated_amount = delegated_amount.into(); + + if delegated_amount == 0 { + source_account.delegate.clear(); + } + } + _ => { + validate_owner(program_id, &source_account.owner, authority_info, remaining)?; + } + } + } + + if amount == 0 { + check_account_owner(program_id, source_account_info)?; + check_account_owner(program_id, mint_info)?; + } + + source_account.amount = updated_source_amount.into(); + + let mint_supply = u64::from(mint.supply) + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + mint.supply = mint_supply.into(); + + Ok(()) +} diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs new file mode 100644 index 0000000..8176ed3 --- /dev/null +++ b/p-token/src/processor/shared/initialize_account.rs @@ -0,0 +1,101 @@ +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::Pubkey, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, +}; +use std::mem::size_of; +use token_interface::{ + error::TokenError, + native_mint::is_native_mint, + state::{ + account::{Account, AccountState}, + mint::Mint, + PodCOption, + }, +}; + +use crate::processor::check_account_owner; + +#[inline(always)] +pub fn process_initialize_account( + program_id: &Pubkey, + accounts: &[AccountInfo], + owner: Option<&Pubkey>, + rent_sysvar_account: bool, +) -> ProgramResult { + let (new_account_info, mint_info, owner, remaning) = if let Some(owner) = owner { + let [new_account_info, mint_info, remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (new_account_info, mint_info, owner, remaning) + } else { + let [new_account_info, mint_info, owner_info, remaning @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (new_account_info, mint_info, owner_info.key(), remaning) + }; + + // Check rent-exempt status of the token account. + + let is_exempt = if rent_sysvar_account { + let rent_sysvar_info = remaning.first().ok_or(ProgramError::NotEnoughAccountKeys)?; + let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + rent.is_exempt(new_account_info.lamports(), size_of::()) + } else { + Rent::get()?.is_exempt(new_account_info.lamports(), size_of::()) + }; + + if !is_exempt { + return Err(TokenError::NotRentExempt.into()); + } + + let account_data = unsafe { new_account_info.borrow_mut_data_unchecked() }; + let account = bytemuck::try_from_bytes_mut::(account_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if account.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } + + let is_native_mint = is_native_mint(mint_info.key()); + + if !is_native_mint { + check_account_owner(program_id, mint_info)?; + + let mint_data = unsafe { mint_info.borrow_data_unchecked() }; + let mint = bytemuck::try_from_bytes::(mint_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if !bool::from(mint.is_initialized) { + return Err(TokenError::InvalidMint.into()); + } + } + + account.mint = *mint_info.key(); + account.owner = *owner; + account.close_authority.clear(); + account.delegate.clear(); + account.delegated_amount = 0u64.into(); + account.state = AccountState::Initialized as u8; + + if is_native_mint { + let rent = Rent::get()?; + let rent_exempt_reserve = rent.minimum_balance(size_of::()); + + account.is_native = PodCOption::from(Some(rent_exempt_reserve.into())); + unsafe { + account.amount = new_account_info + .borrow_lamports_unchecked() + .checked_sub(rent_exempt_reserve) + .ok_or(TokenError::Overflow)? + .into() + } + } else { + account.is_native.clear(); + account.amount = 0u64.into(); + }; + + Ok(()) +} diff --git a/p-token/src/processor/shared/initialize_mint.rs b/p-token/src/processor/shared/initialize_mint.rs new file mode 100644 index 0000000..845b64b --- /dev/null +++ b/p-token/src/processor/shared/initialize_mint.rs @@ -0,0 +1,106 @@ +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::Pubkey, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, +}; +use std::{marker::PhantomData, mem::size_of}; +use token_interface::{ + error::TokenError, + state::{mint::Mint, PodCOption}, +}; + +#[inline(always)] +pub fn process_initialize_mint( + accounts: &[AccountInfo], + args: &InitializeMint, + rent_sysvar_account: bool, +) -> ProgramResult { + let (mint_info, rent_sysvar_info) = if rent_sysvar_account { + let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (mint_info, Some(rent_sysvar_info)) + } else { + let [mint_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (mint_info, None) + }; + + let mint = + bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if mint.is_initialized.into() { + return Err(TokenError::AlreadyInUse.into()); + } + + // Check rent-exempt status of the mint account. + + let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { + let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + rent.is_exempt(mint_info.lamports(), size_of::()) + } else { + Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) + }; + + if !is_exempt { + return Err(TokenError::NotRentExempt.into()); + } + + // Initialize the mint. + + mint.mint_authority = PodCOption::from(Some(*args.mint_authority())); + mint.decimals = args.decimals(); + mint.is_initialized = true.into(); + + if let Some(freeze_authority) = args.freeze_authority() { + mint.freeze_authority = PodCOption::from(Some(*freeze_authority)); + } + + Ok(()) +} + +/// Instruction data for the `InitializeMint` instruction. +pub struct InitializeMint<'a> { + raw: *const u8, + + _data: PhantomData<&'a [u8]>, +} + +impl InitializeMint<'_> { + pub fn try_from_bytes(bytes: &[u8]) -> Result { + // The minimum expected size of the instruction data. + // - decimals (1 byte) + // - mint_authority (32 bytes) + // - option + freeze_authority (1 byte + 32 bytes) + if bytes.len() < 34 { + return Err(ProgramError::InvalidInstructionData); + } + + Ok(InitializeMint { + raw: bytes.as_ptr(), + _data: PhantomData, + }) + } + + pub fn decimals(&self) -> u8 { + unsafe { *self.raw } + } + + pub fn mint_authority(&self) -> &Pubkey { + unsafe { &*(self.raw.add(1) as *const Pubkey) } + } + + pub fn freeze_authority(&self) -> Option<&Pubkey> { + unsafe { + if *self.raw.add(33) == 0 { + Option::None + } else { + Option::Some(&*(self.raw.add(34) as *const Pubkey)) + } + } + } +} diff --git a/p-token/src/processor/shared/initialize_multisig.rs b/p-token/src/processor/shared/initialize_multisig.rs new file mode 100644 index 0000000..8db95f1 --- /dev/null +++ b/p-token/src/processor/shared/initialize_multisig.rs @@ -0,0 +1,64 @@ +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, +}; +use token_interface::{error::TokenError, state::multisig::Multisig}; + +#[inline(always)] +pub fn process_initialize_multisig( + accounts: &[AccountInfo], + m: u8, + rent_sysvar_account: bool, +) -> ProgramResult { + let (multisig_info, rent_sysvar_info, remaining) = if rent_sysvar_account { + let [multisig_info, rent_sysvar_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (multisig_info, Some(rent_sysvar_info), remaining) + } else { + let [multisig_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (multisig_info, None, remaining) + }; + + let multisig_info_data_len = multisig_info.data_len(); + + let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { + let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) + } else { + Rent::get()?.is_exempt(multisig_info.lamports(), multisig_info_data_len) + }; + + if !is_exempt { + return Err(TokenError::NotRentExempt.into()); + } + + let multisig = bytemuck::try_from_bytes_mut::(unsafe { + multisig_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if multisig.is_initialized.into() { + return Err(TokenError::AlreadyInUse.into()); + } + + multisig.m = m; + multisig.n = remaining.len() as u8; + + if !Multisig::is_valid_signer_index(multisig.n as usize) { + return Err(TokenError::InvalidNumberOfProvidedSigners.into()); + } + if !Multisig::is_valid_signer_index(multisig.m as usize) { + return Err(TokenError::InvalidNumberOfRequiredSigners.into()); + } + for (i, signer_info) in remaining.iter().enumerate() { + multisig.signers[i] = *signer_info.key(); + } + multisig.is_initialized = true.into(); + + Ok(()) +} diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs new file mode 100644 index 0000000..62ca9d7 --- /dev/null +++ b/p-token/src/processor/shared/mint_to.rs @@ -0,0 +1,72 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{ + error::TokenError, + native_mint::is_native_mint, + state::{account::Account, mint::Mint}, +}; + +use crate::processor::{check_account_owner, validate_owner}; + +#[inline(always)] +pub fn process_mint_to( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + expected_decimals: Option, +) -> ProgramResult { + let [mint_info, destination_account_info, owner_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + // destination account + + let account_data = unsafe { destination_account_info.borrow_mut_data_unchecked() }; + let destination_account = bytemuck::try_from_bytes_mut::(account_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if destination_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + if is_native_mint(mint_info.key()) { + return Err(TokenError::NativeNotSupported.into()); + } + + if mint_info.key() != &destination_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mint_data = unsafe { mint_info.borrow_mut_data_unchecked() }; + let mint = bytemuck::try_from_bytes_mut::(mint_data) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if let Some(expected_decimals) = expected_decimals { + if expected_decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + match mint.mint_authority.get() { + Some(mint_authority) => validate_owner(program_id, &mint_authority, owner_info, remaining)?, + None => return Err(TokenError::FixedSupply.into()), + } + + if amount == 0 { + check_account_owner(program_id, mint_info)?; + check_account_owner(program_id, destination_account_info)?; + } + + let destination_amount = u64::from(destination_account.amount) + .checked_add(amount) + .ok_or(ProgramError::InvalidAccountData)?; + destination_account.amount = destination_amount.into(); + + let mint_supply = u64::from(mint.supply) + .checked_add(amount) + .ok_or(ProgramError::InvalidAccountData)?; + mint.supply = mint_supply.into(); + + Ok(()) +} diff --git a/p-token/src/processor/shared/mod.rs b/p-token/src/processor/shared/mod.rs new file mode 100644 index 0000000..634ccab --- /dev/null +++ b/p-token/src/processor/shared/mod.rs @@ -0,0 +1,8 @@ +pub mod approve; +pub mod burn; +pub mod initialize_account; +pub mod initialize_mint; +pub mod initialize_multisig; +pub mod mint_to; +pub mod toggle_account_state; +pub mod transfer; diff --git a/p-token/src/processor/toggle_account_state.rs b/p-token/src/processor/shared/toggle_account_state.rs similarity index 96% rename from p-token/src/processor/toggle_account_state.rs rename to p-token/src/processor/shared/toggle_account_state.rs index 69fbac0..e55ea63 100644 --- a/p-token/src/processor/toggle_account_state.rs +++ b/p-token/src/processor/shared/toggle_account_state.rs @@ -9,8 +9,9 @@ use token_interface::{ }, }; -use super::validate_owner; +use crate::processor::validate_owner; +#[inline(always)] pub fn process_toggle_account_state( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs new file mode 100644 index 0000000..766011b --- /dev/null +++ b/p-token/src/processor/shared/transfer.rs @@ -0,0 +1,162 @@ +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{ + error::TokenError, + native_mint::is_native_mint, + state::{account::Account, mint::Mint, PodCOption}, +}; + +use crate::processor::{check_account_owner, validate_owner}; + +#[inline(always)] +pub fn process_transfer( + program_id: &Pubkey, + accounts: &[AccountInfo], + amount: u64, + expected_decimals: Option, +) -> ProgramResult { + // Accounts expected depends on whether we have the mint `decimals` or not; when we have the + // mint `decimals`, we expect the mint account to be present. + + let ( + source_account_info, + expected_mint_info, + destination_account_info, + authority_info, + remaning, + ) = if let Some(decimals) = expected_decimals { + let [source_account_info, mint_info, destination_account_info, authority_info, remaning @ ..] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + ( + source_account_info, + Some((mint_info, decimals)), + destination_account_info, + authority_info, + remaning, + ) + } else { + let [source_account_info, destination_account_info, authority_info, remaning @ ..] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + ( + source_account_info, + None, + destination_account_info, + authority_info, + remaning, + ) + }; + + // Validates source and destination accounts. + + let source_account = bytemuck::try_from_bytes_mut::(unsafe { + source_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + let destination_account = bytemuck::try_from_bytes_mut::(unsafe { + destination_account_info.borrow_mut_data_unchecked() + }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if source_account.is_frozen() || destination_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + // FEBO: Implicitly validates that the account has enough tokens by calculating the + // remaining amount. The amount is only updated on the account if the transfer + // is successful. + let remaining_amount = u64::from(source_account.amount) + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + + if source_account.mint != destination_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + // Validates the mint information. + + if let Some((mint_info, decimals)) = expected_mint_info { + if mint_info.key() != &source_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + let mint = + bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) + .map_err(|_error| ProgramError::InvalidAccountData)?; + + if decimals != mint.decimals { + return Err(TokenError::MintDecimalsMismatch.into()); + } + } + + let self_transfer = source_account_info.key() == destination_account_info.key(); + + // Validates the authority (delegate or owner). + + if source_account.delegate.as_ref() == Some(authority_info.key()) { + validate_owner(program_id, authority_info.key(), authority_info, remaning)?; + + let delegated_amount = u64::from(source_account.delegated_amount) + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + + if !self_transfer { + source_account.delegated_amount = delegated_amount.into(); + + if delegated_amount == 0 { + source_account.delegate = PodCOption::from(None); + } + } + } else { + validate_owner(program_id, &source_account.owner, authority_info, remaning)?; + } + + if self_transfer || amount == 0 { + check_account_owner(program_id, source_account_info)?; + check_account_owner(program_id, destination_account_info)?; + + // No need to move tokens around. + return Ok(()); + } + + // FEBO: This was moved to the if statement above since we can skip the amount + // manipulation if it is a self-transfer or the amount is zero. + // + // This check MUST occur just before the amounts are manipulated + // to ensure self-transfers are fully validated + /* + if self_transfer { + return Ok(()); + } + */ + + // Moves the tokens. + + source_account.amount = remaining_amount.into(); + + let destination_amount = u64::from(destination_account.amount) + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + destination_account.amount = destination_amount.into(); + + if is_native_mint(&source_account.mint) { + let mut source_lamports = source_account_info.try_borrow_mut_lamports()?; + *source_lamports = source_lamports + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + + let mut destination_lamports = destination_account_info.try_borrow_mut_lamports()?; + *destination_lamports = destination_lamports + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + } + + Ok(()) +} diff --git a/p-token/src/processor/thaw_account.rs b/p-token/src/processor/thaw_account.rs index a7f4da0..bd964aa 100644 --- a/p-token/src/processor/thaw_account.rs +++ b/p-token/src/processor/thaw_account.rs @@ -1,8 +1,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::toggle_account_state::process_toggle_account_state; +use super::shared::toggle_account_state::process_toggle_account_state; -#[inline(always)] pub fn process_thaw_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { process_toggle_account_state(program_id, accounts, false) } diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs index 92db0cc..79f1a87 100644 --- a/p-token/src/processor/transfer.rs +++ b/p-token/src/processor/transfer.rs @@ -1,161 +1,11 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; -use token_interface::{ - error::TokenError, - native_mint::is_native_mint, - state::{account::Account, mint::Mint, PodCOption}, -}; +use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; -use super::{check_account_owner, validate_owner}; +use super::shared; pub fn process_transfer( program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, - expected_decimals: Option, ) -> ProgramResult { - // Accounts expected depends on whether we have the mint `decimals` or not; when we have the - // mint `decimals`, we expect the mint account to be present. - - let ( - source_account_info, - expected_mint_info, - destination_account_info, - authority_info, - remaning, - ) = if let Some(decimals) = expected_decimals { - let [source_account_info, mint_info, destination_account_info, authority_info, remaning @ ..] = - accounts - else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - ( - source_account_info, - Some((mint_info, decimals)), - destination_account_info, - authority_info, - remaning, - ) - } else { - let [source_account_info, destination_account_info, authority_info, remaning @ ..] = - accounts - else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - ( - source_account_info, - None, - destination_account_info, - authority_info, - remaning, - ) - }; - - // Validates source and destination accounts. - - let source_account = bytemuck::try_from_bytes_mut::(unsafe { - source_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - let destination_account = bytemuck::try_from_bytes_mut::(unsafe { - destination_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if source_account.is_frozen() || destination_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } - - // FEBO: Implicitly validates that the account has enough tokens by calculating the - // remaining amount. The amount is only updated on the account if the transfer - // is successful. - let remaining_amount = u64::from(source_account.amount) - .checked_sub(amount) - .ok_or(TokenError::InsufficientFunds)?; - - if source_account.mint != destination_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - // Validates the mint information. - - if let Some((mint_info, decimals)) = expected_mint_info { - if mint_info.key() != &source_account.mint { - return Err(TokenError::MintMismatch.into()); - } - - let mint = - bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if decimals != mint.decimals { - return Err(TokenError::MintDecimalsMismatch.into()); - } - } - - let self_transfer = source_account_info.key() == destination_account_info.key(); - - // Validates the authority (delegate or owner). - - if source_account.delegate.as_ref() == Some(authority_info.key()) { - validate_owner(program_id, authority_info.key(), authority_info, remaning)?; - - let delegated_amount = u64::from(source_account.delegated_amount) - .checked_sub(amount) - .ok_or(TokenError::InsufficientFunds)?; - - if !self_transfer { - source_account.delegated_amount = delegated_amount.into(); - - if delegated_amount == 0 { - source_account.delegate = PodCOption::from(None); - } - } - } else { - validate_owner(program_id, &source_account.owner, authority_info, remaning)?; - } - - if self_transfer || amount == 0 { - check_account_owner(program_id, source_account_info)?; - check_account_owner(program_id, destination_account_info)?; - - // No need to move tokens around. - return Ok(()); - } - - // FEBO: This was moved to the if statement above since we can skip the amount - // manipulation if it is a self-transfer or the amount is zero. - // - // This check MUST occur just before the amounts are manipulated - // to ensure self-transfers are fully validated - /* - if self_transfer { - return Ok(()); - } - */ - - // Moves the tokens. - - source_account.amount = remaining_amount.into(); - - let destination_amount = u64::from(destination_account.amount) - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - destination_account.amount = destination_amount.into(); - - if is_native_mint(&source_account.mint) { - let mut source_lamports = source_account_info.try_borrow_mut_lamports()?; - *source_lamports = source_lamports - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - - let mut destination_lamports = destination_account_info.try_borrow_mut_lamports()?; - *destination_lamports = destination_lamports - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - } - - Ok(()) + shared::transfer::process_transfer(program_id, accounts, amount, None) } diff --git a/p-token/src/processor/transfer_checked.rs b/p-token/src/processor/transfer_checked.rs index 60f4cda..8b216c5 100644 --- a/p-token/src/processor/transfer_checked.rs +++ b/p-token/src/processor/transfer_checked.rs @@ -4,7 +4,7 @@ use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use super::transfer::process_transfer; +use super::shared; #[inline(always)] pub fn process_transfer_checked( @@ -13,7 +13,7 @@ pub fn process_transfer_checked( amount: u64, decimals: u8, ) -> ProgramResult { - process_transfer(program_id, accounts, amount, Some(decimals)) + shared::transfer::process_transfer(program_id, accounts, amount, Some(decimals)) } pub struct TransferChecked<'a> { From e17d9eb00e82af90405d35a7e2d0c72f947c462f Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 21 Nov 2024 16:15:19 +0000 Subject: [PATCH 279/335] Tweak inlines --- p-token/src/processor/amount_to_ui_amount.rs | 1 + p-token/src/processor/approve.rs | 1 + p-token/src/processor/approve_checked.rs | 2 +- p-token/src/processor/burn.rs | 1 + p-token/src/processor/burn_checked.rs | 2 +- p-token/src/processor/close_account.rs | 2 +- p-token/src/processor/freeze_account.rs | 1 + p-token/src/processor/get_account_data_size.rs | 1 + p-token/src/processor/initialize_account.rs | 1 + p-token/src/processor/initialize_account2.rs | 2 +- p-token/src/processor/initialize_account3.rs | 2 +- p-token/src/processor/initialize_immutable_owner.rs | 1 + p-token/src/processor/initialize_mint.rs | 1 + p-token/src/processor/initialize_mint2.rs | 2 +- p-token/src/processor/initialize_multisig.rs | 1 + p-token/src/processor/initialize_multisig2.rs | 2 +- p-token/src/processor/mint_to.rs | 1 + p-token/src/processor/mint_to_checked.rs | 2 +- p-token/src/processor/revoke.rs | 2 +- p-token/src/processor/set_authority.rs | 1 + p-token/src/processor/sync_native.rs | 1 + p-token/src/processor/thaw_account.rs | 1 + p-token/src/processor/transfer.rs | 1 + p-token/src/processor/transfer_checked.rs | 2 +- p-token/src/processor/ui_amount_to_amount.rs | 1 + 25 files changed, 25 insertions(+), 10 deletions(-) diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 4f661d2..432c256 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -6,6 +6,7 @@ use token_interface::{error::TokenError, state::mint::Mint}; use super::{amount_to_ui_amount_string_trimmed, check_account_owner}; +#[inline(never)] pub fn process_amount_to_ui_amount( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/approve.rs b/p-token/src/processor/approve.rs index 6a6d1cd..2f8029d 100644 --- a/p-token/src/processor/approve.rs +++ b/p-token/src/processor/approve.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; +#[inline(never)] pub fn process_approve( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/approve_checked.rs b/p-token/src/processor/approve_checked.rs index 6495712..e871b26 100644 --- a/p-token/src/processor/approve_checked.rs +++ b/p-token/src/processor/approve_checked.rs @@ -6,7 +6,7 @@ use pinocchio::{ use super::shared; -#[inline(always)] +#[inline(never)] pub fn process_approve_checked( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/burn.rs b/p-token/src/processor/burn.rs index 34aa606..42614e1 100644 --- a/p-token/src/processor/burn.rs +++ b/p-token/src/processor/burn.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; +#[inline(never)] pub fn process_burn(program_id: &Pubkey, accounts: &[AccountInfo], amount: u64) -> ProgramResult { shared::burn::process_burn(program_id, accounts, amount, None) } diff --git a/p-token/src/processor/burn_checked.rs b/p-token/src/processor/burn_checked.rs index aac4d6d..a32b753 100644 --- a/p-token/src/processor/burn_checked.rs +++ b/p-token/src/processor/burn_checked.rs @@ -6,7 +6,7 @@ use pinocchio::{ use super::shared; -#[inline(always)] +#[inline(never)] pub fn process_burn_checked( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs index b20535c..62850ab 100644 --- a/p-token/src/processor/close_account.rs +++ b/p-token/src/processor/close_account.rs @@ -5,7 +5,7 @@ use token_interface::{error::TokenError, state::account::Account}; use super::{is_owned_by_system_program_or_incinerator, validate_owner, INCINERATOR_ID}; -/// Processes a [CloseAccount](enum.TokenInstruction.html) instruction. +#[inline(never)] pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { let [source_account_info, destination_account_info, authority_info, remaining @ ..] = accounts else { diff --git a/p-token/src/processor/freeze_account.rs b/p-token/src/processor/freeze_account.rs index 910f9ee..4348ccf 100644 --- a/p-token/src/processor/freeze_account.rs +++ b/p-token/src/processor/freeze_account.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared::toggle_account_state::process_toggle_account_state; +#[inline(never)] pub fn process_freeze_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { process_toggle_account_state(program_id, accounts, true) } diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index a886914..ff6e3d1 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -6,6 +6,7 @@ use token_interface::state::{account::Account, mint::Mint}; use super::check_account_owner; +#[inline(never)] pub fn process_get_account_data_size( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs index fd2dab8..a046f6a 100644 --- a/p-token/src/processor/initialize_account.rs +++ b/p-token/src/processor/initialize_account.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; +#[inline(never)] pub fn process_initialize_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { shared::initialize_account::process_initialize_account(program_id, accounts, None, true) } diff --git a/p-token/src/processor/initialize_account2.rs b/p-token/src/processor/initialize_account2.rs index d199b32..ab2f65d 100644 --- a/p-token/src/processor/initialize_account2.rs +++ b/p-token/src/processor/initialize_account2.rs @@ -2,7 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; -#[inline(always)] +#[inline(never)] pub fn process_initialize_account2( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/initialize_account3.rs b/p-token/src/processor/initialize_account3.rs index 82ed1b5..4287389 100644 --- a/p-token/src/processor/initialize_account3.rs +++ b/p-token/src/processor/initialize_account3.rs @@ -2,7 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; -#[inline(always)] +#[inline(never)] pub fn process_initialize_account3( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs index 579c2ce..cdbc688 100644 --- a/p-token/src/processor/initialize_immutable_owner.rs +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -1,6 +1,7 @@ use pinocchio::{account_info::AccountInfo, msg, program_error::ProgramError, ProgramResult}; use token_interface::{error::TokenError, state::account::Account}; +#[inline(never)] pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { let token_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 5601015..4d6de79 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; use super::shared::{self, initialize_mint::InitializeMint}; +#[inline(never)] pub fn process_initialize_mint(accounts: &[AccountInfo], args: &InitializeMint) -> ProgramResult { shared::initialize_mint::process_initialize_mint(accounts, args, true) } diff --git a/p-token/src/processor/initialize_mint2.rs b/p-token/src/processor/initialize_mint2.rs index 663104c..5387566 100644 --- a/p-token/src/processor/initialize_mint2.rs +++ b/p-token/src/processor/initialize_mint2.rs @@ -2,7 +2,7 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; use super::shared::{self, initialize_mint::InitializeMint}; -#[inline(always)] +#[inline(never)] pub fn process_initialize_mint2(accounts: &[AccountInfo], args: &InitializeMint) -> ProgramResult { shared::initialize_mint::process_initialize_mint(accounts, args, false) } diff --git a/p-token/src/processor/initialize_multisig.rs b/p-token/src/processor/initialize_multisig.rs index 53fc939..7fddab5 100644 --- a/p-token/src/processor/initialize_multisig.rs +++ b/p-token/src/processor/initialize_multisig.rs @@ -6,6 +6,7 @@ use pinocchio::{ }; use token_interface::{error::TokenError, state::multisig::Multisig}; +#[inline(never)] pub fn process_initialize_multisig( accounts: &[AccountInfo], m: u8, diff --git a/p-token/src/processor/initialize_multisig2.rs b/p-token/src/processor/initialize_multisig2.rs index 089d05b..9dfbf96 100644 --- a/p-token/src/processor/initialize_multisig2.rs +++ b/p-token/src/processor/initialize_multisig2.rs @@ -2,7 +2,7 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; use super::shared; -#[inline(always)] +#[inline(never)] pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { shared::initialize_multisig::process_initialize_multisig(accounts, m, false) } diff --git a/p-token/src/processor/mint_to.rs b/p-token/src/processor/mint_to.rs index eaea29b..3dadbc1 100644 --- a/p-token/src/processor/mint_to.rs +++ b/p-token/src/processor/mint_to.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; +#[inline(never)] pub fn process_mint_to( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/mint_to_checked.rs b/p-token/src/processor/mint_to_checked.rs index deb8d8e..25684d4 100644 --- a/p-token/src/processor/mint_to_checked.rs +++ b/p-token/src/processor/mint_to_checked.rs @@ -6,7 +6,7 @@ use pinocchio::{ use super::shared; -#[inline(always)] +#[inline(never)] pub fn process_mint_to_checked( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs index 49de485..c77d8b2 100644 --- a/p-token/src/processor/revoke.rs +++ b/p-token/src/processor/revoke.rs @@ -5,7 +5,7 @@ use token_interface::{error::TokenError, state::account::Account}; use super::validate_owner; -/// Processes an [Revoke](enum.TokenInstruction.html) instruction. +#[inline(never)] pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { let [source_account_info, owner_info, remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index e2438e8..f0ed452 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -12,6 +12,7 @@ use token_interface::{ use super::validate_owner; +#[inline(never)] pub fn process_set_authority( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/sync_native.rs b/p-token/src/processor/sync_native.rs index abbe161..25b2029 100644 --- a/p-token/src/processor/sync_native.rs +++ b/p-token/src/processor/sync_native.rs @@ -5,6 +5,7 @@ use token_interface::{error::TokenError, state::account::Account}; use super::check_account_owner; +#[inline(never)] pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { let native_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; diff --git a/p-token/src/processor/thaw_account.rs b/p-token/src/processor/thaw_account.rs index bd964aa..00ea088 100644 --- a/p-token/src/processor/thaw_account.rs +++ b/p-token/src/processor/thaw_account.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared::toggle_account_state::process_toggle_account_state; +#[inline(never)] pub fn process_thaw_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { process_toggle_account_state(program_id, accounts, false) } diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs index 79f1a87..254134b 100644 --- a/p-token/src/processor/transfer.rs +++ b/p-token/src/processor/transfer.rs @@ -2,6 +2,7 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; +#[inline(never)] pub fn process_transfer( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/transfer_checked.rs b/p-token/src/processor/transfer_checked.rs index 8b216c5..1ebcdcd 100644 --- a/p-token/src/processor/transfer_checked.rs +++ b/p-token/src/processor/transfer_checked.rs @@ -6,7 +6,7 @@ use pinocchio::{ use super::shared; -#[inline(always)] +#[inline(never)] pub fn process_transfer_checked( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index b2382a2..4f3dbca 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -6,6 +6,7 @@ use token_interface::{error::TokenError, state::mint::Mint}; use super::{check_account_owner, try_ui_amount_into_amount}; +#[inline(never)] pub fn process_ui_amount_to_amount( program_id: &Pubkey, accounts: &[AccountInfo], From ecc3f85a8ad9472a79a35bed01fd7f139a418a4e Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 21 Nov 2024 16:16:34 +0000 Subject: [PATCH 280/335] Fix typo --- p-token/src/entrypoint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index bdbee3f..021227c 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -112,7 +112,7 @@ pub fn process_instruction( instruction.new_authority, ) } - // 7 - InitializeMint + // 7 - MintTo Some((&7, data)) => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: MintTo"); From a556e623612f4ddd59203d9f5a8b55c5d0a2ea19 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Sun, 24 Nov 2024 11:41:20 +0000 Subject: [PATCH 281/335] processor: Split processor (#2) * Use instruction args * Refactor processor * Update compute table * Remove bytemuck * Move state to interface crate * Update lib comment * Update CU values --- interface/Cargo.toml | 1 - interface/src/instruction.rs | 26 +- interface/src/state/account.rs | 207 ++++++++++---- interface/src/state/account_state.rs | 15 + interface/src/state/mint.rs | 149 +++++++++- interface/src/state/mod.rs | 161 +---------- interface/src/state/multisig.rs | 90 +++++- p-token/Cargo.toml | 1 - p-token/src/entrypoint.rs | 269 ++++++++---------- p-token/src/lib.rs | 2 +- p-token/src/processor/amount_to_ui_amount.rs | 22 +- p-token/src/processor/approve.rs | 18 +- p-token/src/processor/approve_checked.rs | 58 +--- p-token/src/processor/burn.rs | 14 +- p-token/src/processor/burn_checked.rs | 62 ++-- p-token/src/processor/close_account.rs | 20 +- p-token/src/processor/freeze_account.rs | 8 +- .../src/processor/get_account_data_size.rs | 16 +- p-token/src/processor/initialize_account.rs | 8 +- p-token/src/processor/initialize_account2.rs | 8 +- p-token/src/processor/initialize_account3.rs | 8 +- .../processor/initialize_immutable_owner.rs | 8 +- p-token/src/processor/initialize_mint.rs | 113 +++++++- p-token/src/processor/initialize_mint2.rs | 11 +- p-token/src/processor/initialize_multisig.rs | 67 +---- p-token/src/processor/initialize_multisig2.rs | 14 +- p-token/src/processor/mint_to.rs | 18 +- p-token/src/processor/mint_to_checked.rs | 59 ++-- p-token/src/processor/mod.rs | 48 +++- p-token/src/processor/revoke.rs | 20 +- p-token/src/processor/set_authority.rs | 140 +++++---- p-token/src/processor/shared/approve.rs | 29 +- p-token/src/processor/shared/burn.rs | 56 ++-- .../processor/shared/initialize_account.rs | 48 ++-- .../src/processor/shared/initialize_mint.rs | 106 ------- .../processor/shared/initialize_multisig.rs | 15 +- p-token/src/processor/shared/mint_to.rs | 37 ++- p-token/src/processor/shared/mod.rs | 6 +- .../processor/shared/toggle_account_state.rs | 34 +-- p-token/src/processor/shared/transfer.rs | 82 +++--- p-token/src/processor/sync_native.rs | 24 +- p-token/src/processor/thaw_account.rs | 8 +- p-token/src/processor/transfer.rs | 18 +- p-token/src/processor/transfer_checked.rs | 59 ++-- p-token/src/processor/ui_amount_to_amount.rs | 19 +- 45 files changed, 1084 insertions(+), 1118 deletions(-) create mode 100644 interface/src/state/account_state.rs delete mode 100644 p-token/src/processor/shared/initialize_mint.rs diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 628cb2a..fb26855 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -8,6 +8,5 @@ repository = { workspace = true } publish = false [dependencies] -bytemuck = { workspace = true } pinocchio = { workspace = true } pinocchio-pubkey = { workspace = true } diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index c78e6bb..a829e9a 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -1,8 +1,8 @@ -//! Instruction types +//! Instruction types. -use pinocchio::pubkey::Pubkey; +use pinocchio::{program_error::ProgramError, pubkey::Pubkey}; -use crate::state::PodCOption; +use crate::error::TokenError; /// Instructions supported by the token program. #[repr(C)] @@ -27,7 +27,7 @@ pub enum TokenInstruction<'a> { /// The authority/multisignature to mint tokens. mint_authority: Pubkey, /// The freeze authority/multisignature of the mint. - freeze_authority: PodCOption, + freeze_authority: Option, }, /// Initializes a new account to hold tokens. If this account is associated @@ -147,7 +147,7 @@ pub enum TokenInstruction<'a> { /// The type of authority to update. authority_type: AuthorityType, /// The new authority - new_authority: PodCOption, + new_authority: Option, }, /// Mints new tokens to an account. The native mint does not support @@ -416,7 +416,7 @@ pub enum TokenInstruction<'a> { /// The authority/multisignature to mint tokens. mint_authority: Pubkey, /// The freeze authority/multisignature of the mint. - freeze_authority: PodCOption, + freeze_authority: Option, }, /// Gets the required size of an account for the given mint as a @@ -482,7 +482,7 @@ pub enum TokenInstruction<'a> { // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility } -/// Specifies the authority type for SetAuthority instructions +/// Specifies the authority type for `SetAuthority` instructions #[repr(u8)] #[derive(Clone, Debug, PartialEq)] pub enum AuthorityType { @@ -506,13 +506,13 @@ impl AuthorityType { } } - pub fn from(index: u8) -> Self { + pub fn from(index: u8) -> Result { match index { - 0 => AuthorityType::MintTokens, - 1 => AuthorityType::FreezeAccount, - 2 => AuthorityType::AccountOwner, - 3 => AuthorityType::CloseAccount, - _ => panic!("invalid authority type: {index}"), + 0 => Ok(AuthorityType::MintTokens), + 1 => Ok(AuthorityType::FreezeAccount), + 2 => Ok(AuthorityType::AccountOwner), + 3 => Ok(AuthorityType::CloseAccount), + _ => Err(TokenError::InvalidInstruction.into()), } } } diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index e88b48d..fbe6377 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -1,11 +1,15 @@ -use bytemuck::{Pod, Zeroable}; -use pinocchio::pubkey::Pubkey; +use pinocchio::{ + account_info::{AccountInfo, Ref}, + program_error::ProgramError, + pubkey::Pubkey, +}; -use super::{PodCOption, PodU64}; +use crate::program::ID; -/// Account data. +use super::{account_state::AccountState, COption}; + +/// Internal representation of a token account data. #[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] pub struct Account { /// The mint associated with this account pub mint: Pubkey, @@ -14,82 +18,179 @@ pub struct Account { pub owner: Pubkey, /// The amount of tokens this account holds. - pub amount: PodU64, + amount: [u8; 8], /// If `delegate` is `Some` then `delegated_amount` represents - /// the amount authorized by the delegate - pub delegate: PodCOption, + /// the amount authorized by the delegate. + delegate: COption, + + /// The account's state. + pub state: AccountState, - /// The account's state - pub state: u8, + /// Indicates whether this account represents a native token or not. + is_native: [u8; 4], /// If is_native.is_some, this is a native token, and the value logs the /// rent-exempt reserve. An Account is required to be rent-exempt, so /// the value is used by the Processor to ensure that wrapped SOL /// accounts do not drop below this threshold. - pub is_native: PodCOption, + native_amount: [u8; 8], - /// The amount delegated - pub delegated_amount: PodU64, + /// The amount delegated. + delegated_amount: [u8; 8], /// Optional authority to close the account. - pub close_authority: PodCOption, + close_authority: COption, } impl Account { - /// Size of the `Account` account. - pub const LEN: usize = core::mem::size_of::(); + pub const LEN: usize = core::mem::size_of::(); + /// Return a `TokenAccount` from the given account info. + /// + /// This method performs owner and length validation on `AccountInfo`, safe borrowing + /// the account data. #[inline] - pub fn is_initialized(&self) -> bool { - self.state != AccountState::Uninitialized as u8 + pub fn from_account_info(account_info: &AccountInfo) -> Result, ProgramError> { + if account_info.data_len() != Self::LEN { + return Err(ProgramError::InvalidAccountData); + } + if account_info.owner() != &ID { + return Err(ProgramError::InvalidAccountData); + } + Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe { + Self::from_bytes(data) + })) } + /// Return a `TokenAccount` from the given account info. + /// + /// This method performs owner and length validation on `AccountInfo`, but does not + /// perform the borrow check. + /// + /// # Safety + /// + /// The caller must ensure that it is safe to borrow the account data – e.g., there are + /// no mutable borrows of the account data. #[inline] - pub fn is_frozen(&self) -> bool { - self.state == AccountState::Frozen as u8 + pub unsafe fn from_account_info_unchecked( + account_info: &AccountInfo, + ) -> Result<&Account, ProgramError> { + if account_info.data_len() != Self::LEN { + return Err(ProgramError::InvalidAccountData); + } + if account_info.owner() != &ID { + return Err(ProgramError::InvalidAccountData); + } + Ok(Self::from_bytes(account_info.borrow_data_unchecked())) + } + + /// Return a `TokenAccount` from the given bytes. + /// + /// # Safety + /// + /// The caller must ensure that `bytes` contains a valid representation of `TokenAccount`. + #[inline(always)] + pub unsafe fn from_bytes(bytes: &[u8]) -> &Self { + &*(bytes.as_ptr() as *const Account) } + /// Return a mutable `Mint` reference from the given bytes. + /// + /// # Safety + /// + /// The caller must ensure that `bytes` contains a valid representation of `Mint`. + #[inline(always)] + pub unsafe fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self { + &mut *(bytes.as_mut_ptr() as *mut Account) + } + + #[inline] + pub fn set_amount(&mut self, amount: u64) { + self.amount = amount.to_le_bytes(); + } + + #[inline] pub fn amount(&self) -> u64 { - self.amount.into() + u64::from_le_bytes(self.amount) } -} -/// Account state. -#[repr(u8)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub enum AccountState { - /// Account is not yet initialized - #[default] - Uninitialized, - - /// Account is initialized; the account owner and/or delegate may perform - /// permitted operations on this account - Initialized, - - /// Account has been frozen by the mint freeze authority. Neither the - /// account owner nor the delegate are able to perform operations on - /// this account. - Frozen, -} + #[inline] + pub fn clear_delegate(&mut self) { + self.delegate.0[0] = 0; + } -impl From for AccountState { - fn from(value: u8) -> Self { - match value { - 0 => AccountState::Uninitialized, - 1 => AccountState::Initialized, - 2 => AccountState::Frozen, - _ => panic!("invalid account state value: {value}"), + #[inline] + pub fn set_delegate(&mut self, delegate: &Pubkey) { + self.delegate.0[0] = 1; + self.delegate.1 = *delegate; + } + + #[inline] + pub fn delegate(&self) -> Option<&Pubkey> { + if self.delegate.0[0] == 1 { + Some(&self.delegate.1) + } else { + None } } -} -impl From for u8 { - fn from(value: AccountState) -> Self { - match value { - AccountState::Uninitialized => 0, - AccountState::Initialized => 1, - AccountState::Frozen => 2, + #[inline] + pub fn set_native(&mut self, value: bool) { + self.is_native[0] = value as u8; + } + + #[inline] + pub fn is_native(&self) -> bool { + self.is_native[0] == 1 + } + + #[inline] + pub fn native_amount(&self) -> Option { + if self.is_native() { + Some(u64::from_le_bytes(self.native_amount)) + } else { + None } } + + #[inline] + pub fn set_delegated_amount(&mut self, amount: u64) { + self.delegated_amount = amount.to_le_bytes(); + } + + #[inline] + pub fn delegated_amount(&self) -> u64 { + u64::from_le_bytes(self.delegated_amount) + } + + #[inline] + pub fn clear_close_authority(&mut self) { + self.close_authority.0[0] = 0; + } + + #[inline] + pub fn set_close_authority(&mut self, value: &Pubkey) { + self.close_authority.0[0] = 1; + self.close_authority.1 = *value; + } + + #[inline] + pub fn close_authority(&self) -> Option<&Pubkey> { + if self.close_authority.0[0] == 1 { + Some(&self.close_authority.1) + } else { + None + } + } + + #[inline(always)] + pub fn is_initialized(&self) -> bool { + self.state != AccountState::Uninitialized + } + + #[inline(always)] + pub fn is_frozen(&self) -> bool { + self.state == AccountState::Frozen + } } diff --git a/interface/src/state/account_state.rs b/interface/src/state/account_state.rs new file mode 100644 index 0000000..6747757 --- /dev/null +++ b/interface/src/state/account_state.rs @@ -0,0 +1,15 @@ +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum AccountState { + /// Account is not yet initialized + Uninitialized, + + /// Account is initialized; the account owner and/or delegate may perform + /// permitted operations on this account + Initialized, + + /// Account has been frozen by the mint freeze authority. Neither the + /// account owner nor the delegate are able to perform operations on + /// this account. + Frozen, +} diff --git a/interface/src/state/mint.rs b/interface/src/state/mint.rs index 50896c6..1ca3d90 100644 --- a/interface/src/state/mint.rs +++ b/interface/src/state/mint.rs @@ -1,32 +1,157 @@ -use bytemuck::{Pod, Zeroable}; -use pinocchio::pubkey::Pubkey; +use pinocchio::{ + account_info::{AccountInfo, Ref}, + program_error::ProgramError, + pubkey::Pubkey, +}; -use super::{PodBool, PodCOption, PodU64}; +use crate::program::ID; -/// Mint data. +use super::COption; + +/// Internal representation of a mint data. #[repr(C)] -#[derive(Clone, Copy, Default, Pod, Zeroable)] pub struct Mint { /// Optional authority used to mint new tokens. The mint authority may only /// be provided during mint creation. If no mint authority is present /// then the mint has a fixed supply and no further tokens may be /// minted. - pub mint_authority: PodCOption, + pub mint_authority: COption, /// Total supply of tokens. - pub supply: PodU64, + supply: [u8; 8], /// Number of base 10 digits to the right of the decimal place. pub decimals: u8, - /// Is `true` if this structure has been initialized - pub is_initialized: PodBool, + /// Is `true` if this structure has been initialized. + is_initialized: u8, + // Indicates whether the freeze authority is present or not. + //freeze_authority_option: [u8; 4], /// Optional authority to freeze token accounts. - pub freeze_authority: PodCOption, + pub freeze_authority: COption, } impl Mint { - /// Size of the `Mint` account. - pub const LEN: usize = core::mem::size_of::(); + /// The length of the `Mint` account data. + pub const LEN: usize = core::mem::size_of::(); + + /// Return a `Mint` from the given account info. + /// + /// This method performs owner and length validation on `AccountInfo`, safe borrowing + /// the account data. + #[inline] + pub fn from_account_info(account_info: &AccountInfo) -> Result, ProgramError> { + if account_info.data_len() != Self::LEN { + return Err(ProgramError::InvalidAccountData); + } + if account_info.owner() != &ID { + return Err(ProgramError::InvalidAccountOwner); + } + Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe { + Self::from_bytes(data) + })) + } + + /// Return a `Mint` from the given account info. + /// + /// This method performs owner and length validation on `AccountInfo`, but does not + /// perform the borrow check. + /// + /// # Safety + /// + /// The caller must ensure that it is safe to borrow the account data – e.g., there are + /// no mutable borrows of the account data. + #[inline] + pub unsafe fn from_account_info_unchecked( + account_info: &AccountInfo, + ) -> Result<&Self, ProgramError> { + if account_info.data_len() != Self::LEN { + return Err(ProgramError::InvalidAccountData); + } + if account_info.owner() != &ID { + return Err(ProgramError::InvalidAccountOwner); + } + Ok(Self::from_bytes(account_info.borrow_data_unchecked())) + } + + /// Return a `Mint` reference from the given bytes. + /// + /// # Safety + /// + /// The caller must ensure that `bytes` contains a valid representation of `Mint`. + #[inline] + pub unsafe fn from_bytes(bytes: &[u8]) -> &Self { + &*(bytes.as_ptr() as *const Mint) + } + + /// Return a mutable `Mint` reference from the given bytes. + /// + /// # Safety + /// + /// The caller must ensure that `bytes` contains a valid representation of `Mint`. + #[inline] + pub unsafe fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self { + &mut *(bytes.as_mut_ptr() as *mut Mint) + } + + #[inline] + pub fn set_supply(&mut self, supply: u64) { + self.supply = supply.to_le_bytes(); + } + + #[inline] + pub fn supply(&self) -> u64 { + u64::from_le_bytes(self.supply) + } + + #[inline] + pub fn set_initialized(&mut self, value: bool) { + self.is_initialized = value as u8; + } + + #[inline] + pub fn is_initialized(&self) -> bool { + self.is_initialized == 1 + } + + #[inline] + pub fn clear_mint_authority(&mut self) { + self.mint_authority.0[0] = 0; + } + + #[inline] + pub fn set_mint_authority(&mut self, mint_authority: &Pubkey) { + self.mint_authority.0[0] = 1; + self.mint_authority.1 = *mint_authority; + } + + #[inline] + pub fn mint_authority(&self) -> Option<&Pubkey> { + if self.mint_authority.0[0] == 1 { + Some(&self.mint_authority.1) + } else { + None + } + } + + #[inline] + pub fn clear_freeze_authority(&mut self) { + self.freeze_authority.0[0] = 0; + } + + #[inline] + pub fn set_freeze_authority(&mut self, freeze_authority: &Pubkey) { + self.freeze_authority.0[0] = 1; + self.freeze_authority.1 = *freeze_authority; + } + + #[inline] + pub fn freeze_authority(&self) -> Option<&Pubkey> { + if self.freeze_authority.0[0] == 1 { + Some(&self.freeze_authority.1) + } else { + None + } + } } diff --git a/interface/src/state/mod.rs b/interface/src/state/mod.rs index a0f8d9b..04c0342 100644 --- a/interface/src/state/mod.rs +++ b/interface/src/state/mod.rs @@ -1,162 +1,7 @@ -use std::mem::align_of; - -use bytemuck::{Pod, Zeroable}; - pub mod account; +pub mod account_state; pub mod mint; pub mod multisig; -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct PodCOption { - /// Indicates if the option is `Some` or `None`. - tag: [u8; 4], - - /// The value of the option. - value: T, -} - -impl From> for PodCOption { - fn from(value: Option) -> Self { - if align_of::() != 1 { - panic!("PodCOption only supports Pod types with alignment 1"); - } - - match value { - Some(value) => Self { - tag: [1, 0, 0, 0], - value, - }, - None => Self { - tag: [0, 0, 0, 0], - value: T::default(), - }, - } - } -} - -impl PodCOption { - pub const NONE: [u8; 4] = [0, 0, 0, 0]; - - pub const SOME: [u8; 4] = [1, 0, 0, 0]; - - pub fn some(value: T) -> Self { - Self { - tag: [1, 0, 0, 0], - value, - } - } - - /// Returns `true` if the option is a `None` value. - #[inline] - pub fn is_none(&self) -> bool { - self.tag == Self::NONE - } - - /// Returns `true` if the option is a `Some` value. - #[inline] - pub fn is_some(&self) -> bool { - !self.is_none() - } - - /// Returns the contained value as an `Option`. - #[inline] - pub fn get(self) -> Option { - if self.is_none() { - None - } else { - Some(self.value) - } - } - - /// Returns the contained value as an `Option`. - #[inline] - pub fn as_ref(&self) -> Option<&T> { - if self.is_none() { - None - } else { - Some(&self.value) - } - } - - /// Returns the contained value as a mutable `Option`. - #[inline] - pub fn as_mut(&mut self) -> Option<&mut T> { - if self.is_none() { - None - } else { - Some(&mut self.value) - } - } - - #[inline] - pub fn set(&mut self, value: T) { - self.tag = Self::SOME; - self.value = value; - } - - #[inline] - pub fn clear(&mut self) { - self.tag = Self::NONE; - // we don't need to zero the value since the tag - // indicates it is a `None` value - } -} - -/// ## Safety -/// -/// `PodCOption` requires a `Pod` type `T` with alignment of 1. -unsafe impl Pod for PodCOption {} - -/// ## Safety -/// -/// `PodCOption` requires a `Pod` type `T` with alignment of 1. -unsafe impl Zeroable for PodCOption {} - -#[repr(C)] -#[derive(Copy, Clone, Default, Pod, Zeroable)] -pub struct PodBool(u8); - -impl From for PodBool { - fn from(b: bool) -> Self { - Self(b.into()) - } -} - -impl From<&bool> for PodBool { - fn from(b: &bool) -> Self { - Self((*b).into()) - } -} - -impl From<&PodBool> for bool { - fn from(b: &PodBool) -> Self { - b.0 != 0 - } -} - -impl From for bool { - fn from(b: PodBool) -> Self { - b.0 != 0 - } -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] -#[repr(C)] -pub struct PodU64(pub [u8; 8]); - -impl PodU64 { - pub const fn from_primitive(n: u64) -> Self { - Self(n.to_le_bytes()) - } -} -impl From for PodU64 { - fn from(n: u64) -> Self { - Self::from_primitive(n) - } -} -impl From for u64 { - fn from(pod: PodU64) -> Self { - Self::from_le_bytes(pod.0) - } -} +/// Type alias for fields represented as `COption`. +pub type COption = ([u8; 4], T); diff --git a/interface/src/state/multisig.rs b/interface/src/state/multisig.rs index d34d2e6..362c614 100644 --- a/interface/src/state/multisig.rs +++ b/interface/src/state/multisig.rs @@ -1,32 +1,108 @@ -use bytemuck::{Pod, Zeroable}; -use pinocchio::pubkey::Pubkey; +use pinocchio::{ + account_info::{AccountInfo, Ref}, + program_error::ProgramError, + pubkey::Pubkey, +}; -use super::PodBool; +use crate::program::ID; /// Minimum number of multisignature signers (min N) pub const MIN_SIGNERS: usize = 1; + /// Maximum number of multisignature signers (max N) pub const MAX_SIGNERS: usize = 11; /// Multisignature data. #[repr(C)] -#[derive(Clone, Copy, Default, Pod, Zeroable)] pub struct Multisig { - /// Number of signers required + /// Number of signers required. pub m: u8, - /// Number of valid signers + + /// Number of valid signers. pub n: u8, + /// Is `true` if this structure has been initialized - pub is_initialized: PodBool, + is_initialized: u8, + /// Signer public keys pub signers: [Pubkey; MAX_SIGNERS], } impl Multisig { + /// The length of the `Multisig` account data. pub const LEN: usize = core::mem::size_of::(); + /// Return a `Multisig` from the given account info. + /// + /// This method performs owner and length validation on `AccountInfo`, safe borrowing + /// the account data. + #[inline] + pub fn from_account_info(account_info: &AccountInfo) -> Result, ProgramError> { + if account_info.data_len() != Self::LEN { + return Err(ProgramError::InvalidAccountData); + } + if account_info.owner() != &ID { + return Err(ProgramError::InvalidAccountOwner); + } + Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe { + Self::from_bytes(data) + })) + } + + /// Return a `Multisig` from the given account info. + /// + /// This method performs owner and length validation on `AccountInfo`, but does not + /// perform the borrow check. + /// + /// # Safety + /// + /// The caller must ensure that it is safe to borrow the account data – e.g., there are + /// no mutable borrows of the account data. + #[inline] + pub unsafe fn from_account_info_unchecked( + account_info: &AccountInfo, + ) -> Result<&Self, ProgramError> { + if account_info.data_len() != Self::LEN { + return Err(ProgramError::InvalidAccountData); + } + if account_info.owner() != &ID { + return Err(ProgramError::InvalidAccountOwner); + } + Ok(Self::from_bytes(account_info.borrow_data_unchecked())) + } + + /// Return a `Multisig` reference from the given bytes. + /// + /// # Safety + /// + /// The caller must ensure that `bytes` contains a valid representation of `Multisig`. + #[inline] + pub unsafe fn from_bytes(bytes: &[u8]) -> &Self { + &*(bytes.as_ptr() as *const Multisig) + } + + /// Return a mutable `Multisig` reference from the given bytes. + /// + /// # Safety + /// + /// The caller must ensure that `bytes` contains a valid representation of `Multisig`. + #[inline] + pub unsafe fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self { + &mut *(bytes.as_mut_ptr() as *mut Multisig) + } + /// Utility function that checks index is between [`MIN_SIGNERS`] and [`MAX_SIGNERS`]. pub fn is_valid_signer_index(index: usize) -> bool { (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) } + + #[inline] + pub fn set_initialized(&mut self, value: bool) { + self.is_initialized = value as u8; + } + + #[inline] + pub fn is_initialized(&self) -> bool { + self.is_initialized == 1 + } } diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 1e2af78..a2608d7 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -18,7 +18,6 @@ logging = [] test-sbf = [] [dependencies] -bytemuck = { workspace = true } pinocchio = { workspace = true } pinocchio-pubkey = { workspace = true } token-interface = { version = "^0", path = "../interface" } diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 021227c..f72845e 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -1,276 +1,229 @@ -use core::str; - use pinocchio::{ account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use crate::processor::{ - amount_to_ui_amount::process_amount_to_ui_amount, - approve::process_approve, - approve_checked::{process_approve_checked, ApproveChecked}, - burn::process_burn, - burn_checked::{process_burn_checked, BurnChecked}, - close_account::process_close_account, - freeze_account::process_freeze_account, - get_account_data_size::process_get_account_data_size, - initialize_account::process_initialize_account, - initialize_account2::process_initialize_account2, - initialize_account3::process_initialize_account3, - initialize_immutable_owner::process_initialize_immutable_owner, - initialize_mint::process_initialize_mint, - initialize_mint2::process_initialize_mint2, - initialize_multisig::process_initialize_multisig, - initialize_multisig2::process_initialize_multisig2, - mint_to::process_mint_to, - mint_to_checked::{process_mint_to_checked, MintToChecked}, - revoke::process_revoke, - set_authority::{process_set_authority, SetAuthority}, - shared::initialize_mint::InitializeMint, - sync_native::process_sync_native, - thaw_account::process_thaw_account, - transfer::process_transfer, - transfer_checked::{process_transfer_checked, TransferChecked}, - ui_amount_to_amount::process_ui_amount_to_amount, -}; +use crate::processor::*; entrypoint!(process_instruction); +/// Process an instruction. +/// +/// The processor of the token program is divided into two parts to reduce the overhead +/// of having a large `match` statement. The first part of the processor handles the +/// most common instructions, while the second part handles the remaining instructions. +/// The rationale is to reduce the overhead of making multiple comparisons for popular +/// instructions. +/// +/// Instructions on the first part of the processor: +/// +/// - `0`: `InitializeMint` +/// - `3`: `Transfer` +/// - `7`: `MintTo` +/// - `9`: `CloseAccount` +/// - `18`: `InitializeAccount3` +/// - `20`: `InitializeMint2` #[inline(always)] pub fn process_instruction( - program_id: &Pubkey, + _program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - match instruction_data.split_first() { + let (discriminator, instruction_data) = instruction_data + .split_first() + .ok_or(ProgramError::InvalidInstructionData)?; + + match *discriminator { // 0 - InitializeMint - Some((&0, data)) => { + 0 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMint"); - let instruction = InitializeMint::try_from_bytes(data)?; + process_initialize_mint(accounts, instruction_data, true) + } - process_initialize_mint(accounts, &instruction) + // 3 - Transfer + 3 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: Transfer"); + + process_transfer(accounts, instruction_data) } - // 1 - InitializeAccount - Some((&1, _)) => { + // 7 - MintTo + 7 => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: InitializeAccount"); + pinocchio::msg!("Instruction: MintTo"); - process_initialize_account(program_id, accounts) + process_mint_to(accounts, instruction_data) } - // 2 - InitializeMultisig - Some((&2, data)) => { + // 9 - CloseAccount + 9 => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: InitializeMultisig"); + pinocchio::msg!("Instruction: CloseAccount"); + + process_close_account(accounts) + } + // 18 - InitializeAccount3 + 18 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeAccount3"); - let m = data.first().ok_or(ProgramError::InvalidInstructionData)?; + process_initialize_account3(accounts, instruction_data) + } + // 20 - InitializeMint2 + 20 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeMint2"); - process_initialize_multisig(accounts, *m, true) + process_initialize_mint2(accounts, instruction_data) } - // 3 - Transfer - Some((&3, data)) => { + _ => process_remaining_instruction(accounts, instruction_data, *discriminator), + } +} + +/// Process the remaining instructions. +/// +/// This function is called by the `process_instruction` function if the discriminator +/// does not match any of the common instructions. This function is used to reduce the +/// overhead of having a large `match` statement in the `process_instruction` function. +fn process_remaining_instruction( + accounts: &[AccountInfo], + instruction_data: &[u8], + discriminator: u8, +) -> ProgramResult { + match discriminator { + // 1 - InitializeAccount + 1 => { #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: Transfer"); + pinocchio::msg!("Instruction: InitializeAccount"); - let amount = u64::from_le_bytes( - data.try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + process_initialize_account(accounts) + } + // 2 - InitializeMultisig + 2 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeMultisig"); - process_transfer(program_id, accounts, amount) + process_initialize_multisig(accounts, instruction_data) } // 4 - Approve - Some((&4, data)) => { + 4 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Approve"); - let amount = u64::from_le_bytes( - data.try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); - - process_approve(program_id, accounts, amount) + process_approve(accounts, instruction_data) } // 5 - Revoke - Some((&5, _)) => { + 5 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Revoke"); - process_revoke(program_id, accounts) + process_revoke(accounts, instruction_data) } // 6 - SetAuthority - Some((&6, data)) => { + 6 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: SetAuthority"); - let instruction = SetAuthority::try_from_bytes(data)?; - process_set_authority( - program_id, - accounts, - instruction.authority_type, - instruction.new_authority, - ) - } - // 7 - MintTo - Some((&7, data)) => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: MintTo"); - - let amount = u64::from_le_bytes( - data.try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); - - process_mint_to(program_id, accounts, amount) + process_set_authority(accounts, instruction_data) } // 8 - Burn - Some((&8, data)) => { + 8 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Burn"); - let amount = u64::from_le_bytes( - data.try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); - - process_burn(program_id, accounts, amount) - } - // 9 - CloseAccount - Some((&9, _)) => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: CloseAccount"); - - process_close_account(program_id, accounts) + process_burn(accounts, instruction_data) } // 10 - FreezeAccount - Some((&10, _)) => { + 10 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: FreezeAccount"); - process_freeze_account(program_id, accounts) + process_freeze_account(accounts) } // 11 - ThawAccount - Some((&11, _)) => { + 11 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ThawAccount"); - process_thaw_account(program_id, accounts) + process_thaw_account(accounts) } // 12 - TransferChecked - Some((&12, data)) => { + 12 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: TransferChecked"); - let args = TransferChecked::try_from_bytes(data)?; - - process_transfer_checked(program_id, accounts, args.amount(), args.decimals()) + process_transfer_checked(accounts, instruction_data) } // 13 - ApproveChecked - Some((&13, data)) => { + 13 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ApproveChecked"); - let args = ApproveChecked::try_from_bytes(data)?; - - process_approve_checked(program_id, accounts, args.amount(), args.decimals()) + process_approve_checked(accounts, instruction_data) } // 14 - MintToChecked - Some((&14, data)) => { + 14 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: MintToChecked"); - let args = MintToChecked::try_from_bytes(data)?; - - process_mint_to_checked(program_id, accounts, args.amount(), args.decimals()) + process_mint_to_checked(accounts, instruction_data) } // 15 - BurnChecked - Some((&15, data)) => { + 15 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: BurnChecked"); - let args = BurnChecked::try_from_bytes(data)?; - - process_burn_checked(program_id, accounts, args.amount(), args.decimals()) + process_burn_checked(accounts, instruction_data) } // 16 - InitializeAccount2 - Some((&16, data)) => { + 16 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeAccount2"); - let owner = unsafe { &*(data.as_ptr() as *const Pubkey) }; - - process_initialize_account2(program_id, accounts, owner) + process_initialize_account2(accounts, instruction_data) } // 17 - SyncNative - Some((&17, _)) => { + 17 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: SyncNative"); - process_sync_native(program_id, accounts) - } - // 18 - InitializeAccount3 - Some((&18, data)) => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: InitializeAccount3"); - - let owner = unsafe { &*(data.as_ptr() as *const Pubkey) }; - - process_initialize_account3(program_id, accounts, owner) + process_sync_native(accounts) } // 19 - InitializeMultisig2 - Some((&19, data)) => { + 19 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMultisig2"); - let m = data.first().ok_or(ProgramError::InvalidInstructionData)?; - - process_initialize_multisig2(accounts, *m) - } - // 20 - InitializeMint2 - Some((&20, data)) => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: InitializeMint2"); - - let instruction = InitializeMint::try_from_bytes(data)?; - - process_initialize_mint2(accounts, &instruction) + process_initialize_multisig2(accounts, instruction_data) } // 21 - GetAccountDataSize - Some((&21, _)) => { + 21 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: GetAccountDataSize"); - process_get_account_data_size(program_id, accounts) + process_get_account_data_size(accounts) } // 22 - InitializeImmutableOwner - Some((&22, _)) => { + 22 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeImmutableOwner"); process_initialize_immutable_owner(accounts) } // 23 - AmountToUiAmount - Some((&23, data)) => { + 23 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: AmountToUiAmount"); - let amount = u64::from_le_bytes( - data.try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); - - process_amount_to_ui_amount(program_id, accounts, amount) + process_amount_to_ui_amount(accounts, instruction_data) } // 24 - UiAmountToAmount - Some((&24, data)) => { + 24 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: UiAmountToAmount"); - let ui_amount = - str::from_utf8(data).map_err(|_error| ProgramError::InvalidInstructionData)?; - - process_ui_amount_to_amount(program_id, accounts, ui_amount) + process_ui_amount_to_amount(accounts, instruction_data) } _ => Err(ProgramError::InvalidInstructionData), } diff --git a/p-token/src/lib.rs b/p-token/src/lib.rs index 3a174fb..8b786ad 100644 --- a/p-token/src/lib.rs +++ b/p-token/src/lib.rs @@ -1,4 +1,4 @@ -//! A lighter Token program for SVM. +//! An ERC20-like Token program for the Solana blockchain. mod entrypoint; mod processor; diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 432c256..3328fdb 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -1,23 +1,25 @@ use pinocchio::{ - account_info::AccountInfo, program::set_return_data, program_error::ProgramError, - pubkey::Pubkey, ProgramResult, + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; -use token_interface::{error::TokenError, state::mint::Mint}; +use token_interface::state::mint::Mint; use super::{amount_to_ui_amount_string_trimmed, check_account_owner}; -#[inline(never)] +#[inline(always)] pub fn process_amount_to_ui_amount( - program_id: &Pubkey, accounts: &[AccountInfo], - amount: u64, + instruction_data: &[u8], ) -> ProgramResult { + let amount = u64::from_le_bytes( + instruction_data + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; - check_account_owner(program_id, mint_info)?; + check_account_owner(mint_info)?; - let mint = - bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) - .map_err(|_error| TokenError::InvalidMint)?; + let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; let ui_amount = amount_to_ui_amount_string_trimmed(amount, mint.decimals); set_return_data(&ui_amount.into_bytes()); diff --git a/p-token/src/processor/approve.rs b/p-token/src/processor/approve.rs index 2f8029d..10c61ed 100644 --- a/p-token/src/processor/approve.rs +++ b/p-token/src/processor/approve.rs @@ -1,12 +1,14 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_approve( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, -) -> ProgramResult { - shared::approve::process_approve(program_id, accounts, amount, None) +#[inline(always)] +pub fn process_approve(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + let amount = u64::from_le_bytes( + instruction_data + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + shared::approve::process_approve(accounts, amount, None) } diff --git a/p-token/src/processor/approve_checked.rs b/p-token/src/processor/approve_checked.rs index e871b26..580a93d 100644 --- a/p-token/src/processor/approve_checked.rs +++ b/p-token/src/processor/approve_checked.rs @@ -1,47 +1,19 @@ -use std::marker::PhantomData; - -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_approve_checked( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - decimals: u8, -) -> ProgramResult { - shared::approve::process_approve(program_id, accounts, amount, Some(decimals)) -} - -pub struct ApproveChecked<'a> { - raw: *const u8, - - _data: PhantomData<&'a [u8]>, -} - -impl ApproveChecked<'_> { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != 9 { - return Err(ProgramError::InvalidInstructionData); - } - - Ok(ApproveChecked { - raw: bytes.as_ptr(), - _data: PhantomData, - }) - } - - pub fn amount(&self) -> u64 { - unsafe { - let amount = self.raw as *const u64; - amount.read_unaligned() - } - } - - pub fn decimals(&self) -> u8 { - unsafe { *self.raw.add(8) } - } +#[inline(always)] +pub fn process_approve_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + let amount = u64::from_le_bytes( + amount + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + shared::approve::process_approve( + accounts, + amount, + Some(*decimals.first().ok_or(ProgramError::InvalidAccountData)?), + ) } diff --git a/p-token/src/processor/burn.rs b/p-token/src/processor/burn.rs index 42614e1..6ceed84 100644 --- a/p-token/src/processor/burn.rs +++ b/p-token/src/processor/burn.rs @@ -1,8 +1,14 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_burn(program_id: &Pubkey, accounts: &[AccountInfo], amount: u64) -> ProgramResult { - shared::burn::process_burn(program_id, accounts, amount, None) +#[inline(always)] +pub fn process_burn(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + let amount = u64::from_le_bytes( + instruction_data + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + shared::burn::process_burn(accounts, amount, None) } diff --git a/p-token/src/processor/burn_checked.rs b/p-token/src/processor/burn_checked.rs index a32b753..f9ef06c 100644 --- a/p-token/src/processor/burn_checked.rs +++ b/p-token/src/processor/burn_checked.rs @@ -1,47 +1,23 @@ -use std::marker::PhantomData; - -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_burn_checked( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - decimals: u8, -) -> ProgramResult { - shared::burn::process_burn(program_id, accounts, amount, Some(decimals)) -} - -pub struct BurnChecked<'a> { - raw: *const u8, - - _data: PhantomData<&'a [u8]>, -} - -impl BurnChecked<'_> { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != 9 { - return Err(ProgramError::InvalidInstructionData); - } - - Ok(BurnChecked { - raw: bytes.as_ptr(), - _data: PhantomData, - }) - } - - pub fn amount(&self) -> u64 { - unsafe { - let amount = self.raw as *const u64; - amount.read_unaligned() - } - } - - pub fn decimals(&self) -> u8 { - unsafe { *self.raw.add(8) } - } +#[inline(always)] +pub fn process_burn_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + let amount = u64::from_le_bytes( + amount + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + shared::burn::process_burn( + accounts, + amount, + Some( + *decimals + .first() + .ok_or(ProgramError::InvalidInstructionData)?, + ), + ) } diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs index 62850ab..31432e7 100644 --- a/p-token/src/processor/close_account.rs +++ b/p-token/src/processor/close_account.rs @@ -1,12 +1,10 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{error::TokenError, state::account::Account}; use super::{is_owned_by_system_program_or_incinerator, validate_owner, INCINERATOR_ID}; -#[inline(never)] -pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { +#[inline(always)] +pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { let [source_account_info, destination_account_info, authority_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -17,20 +15,18 @@ pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> P } let source_account = - bytemuck::try_from_bytes::(unsafe { source_account_info.borrow_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; - if source_account.is_native.is_none() && source_account.amount() != 0 { + if !source_account.is_native() && source_account.amount() != 0 { return Err(TokenError::NonNativeHasBalance.into()); } let authority = source_account - .close_authority - .get() - .unwrap_or(source_account.owner); + .close_authority() + .unwrap_or(&source_account.owner); if !is_owned_by_system_program_or_incinerator(source_account_info.owner()) { - validate_owner(program_id, &authority, authority_info, remaining)?; + validate_owner(authority, authority_info, remaining)?; } else if destination_account_info.key() != &INCINERATOR_ID { return Err(ProgramError::InvalidAccountData); } diff --git a/p-token/src/processor/freeze_account.rs b/p-token/src/processor/freeze_account.rs index 4348ccf..5637611 100644 --- a/p-token/src/processor/freeze_account.rs +++ b/p-token/src/processor/freeze_account.rs @@ -1,8 +1,8 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{account_info::AccountInfo, ProgramResult}; use super::shared::toggle_account_state::process_toggle_account_state; -#[inline(never)] -pub fn process_freeze_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - process_toggle_account_state(program_id, accounts, true) +#[inline(always)] +pub fn process_freeze_account(accounts: &[AccountInfo]) -> ProgramResult { + process_toggle_account_state(accounts, true) } diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index ff6e3d1..5e96960 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -1,24 +1,20 @@ use pinocchio::{ - account_info::AccountInfo, program::set_return_data, program_error::ProgramError, - pubkey::Pubkey, ProgramResult, + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; use token_interface::state::{account::Account, mint::Mint}; use super::check_account_owner; -#[inline(never)] -pub fn process_get_account_data_size( - program_id: &Pubkey, - accounts: &[AccountInfo], -) -> ProgramResult { +#[inline(always)] +pub fn process_get_account_data_size(accounts: &[AccountInfo]) -> ProgramResult { let [mint_info, _remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - check_account_owner(program_id, mint_info)?; + // Make sure the mint is valid. + check_account_owner(mint_info)?; - let _ = bytemuck::try_from_bytes::(unsafe { mint_info.borrow_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let _ = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; set_return_data(&Account::LEN.to_le_bytes()); diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs index a046f6a..2c12509 100644 --- a/p-token/src/processor/initialize_account.rs +++ b/p-token/src/processor/initialize_account.rs @@ -1,8 +1,8 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{account_info::AccountInfo, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_initialize_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - shared::initialize_account::process_initialize_account(program_id, accounts, None, true) +#[inline(always)] +pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { + shared::initialize_account::process_initialize_account(accounts, None, true) } diff --git a/p-token/src/processor/initialize_account2.rs b/p-token/src/processor/initialize_account2.rs index ab2f65d..9200ee0 100644 --- a/p-token/src/processor/initialize_account2.rs +++ b/p-token/src/processor/initialize_account2.rs @@ -2,11 +2,11 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; -#[inline(never)] +#[inline(always)] pub fn process_initialize_account2( - program_id: &Pubkey, accounts: &[AccountInfo], - owner: &Pubkey, + instruction_data: &[u8], ) -> ProgramResult { - shared::initialize_account::process_initialize_account(program_id, accounts, Some(owner), true) + let owner = unsafe { &*(instruction_data.as_ptr() as *const Pubkey) }; + shared::initialize_account::process_initialize_account(accounts, Some(owner), true) } diff --git a/p-token/src/processor/initialize_account3.rs b/p-token/src/processor/initialize_account3.rs index 4287389..4eaa7a5 100644 --- a/p-token/src/processor/initialize_account3.rs +++ b/p-token/src/processor/initialize_account3.rs @@ -2,11 +2,11 @@ use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; use super::shared; -#[inline(never)] +#[inline(always)] pub fn process_initialize_account3( - program_id: &Pubkey, accounts: &[AccountInfo], - owner: &Pubkey, + instruction_data: &[u8], ) -> ProgramResult { - shared::initialize_account::process_initialize_account(program_id, accounts, Some(owner), false) + let owner = unsafe { &*(instruction_data.as_ptr() as *const Pubkey) }; + shared::initialize_account::process_initialize_account(accounts, Some(owner), false) } diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs index cdbc688..766e5b5 100644 --- a/p-token/src/processor/initialize_immutable_owner.rs +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -1,14 +1,12 @@ use pinocchio::{account_info::AccountInfo, msg, program_error::ProgramError, ProgramResult}; use token_interface::{error::TokenError, state::account::Account}; -#[inline(never)] +#[inline(always)] pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { let token_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; - let account = bytemuck::try_from_bytes_mut::(unsafe { - token_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let account = + unsafe { Account::from_bytes_mut(token_account_info.borrow_mut_data_unchecked()) }; if account.is_initialized() { return Err(TokenError::AlreadyInUse.into()); diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 4d6de79..752537d 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -1,8 +1,111 @@ -use pinocchio::{account_info::AccountInfo, ProgramResult}; +use core::{marker::PhantomData, mem::size_of}; +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::Pubkey, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, +}; +use token_interface::{error::TokenError, state::mint::Mint}; -use super::shared::{self, initialize_mint::InitializeMint}; +#[inline(always)] +pub fn process_initialize_mint( + accounts: &[AccountInfo], + instruction_data: &[u8], + rent_sysvar_account: bool, +) -> ProgramResult { + // Validates the instruction data. -#[inline(never)] -pub fn process_initialize_mint(accounts: &[AccountInfo], args: &InitializeMint) -> ProgramResult { - shared::initialize_mint::process_initialize_mint(accounts, args, true) + let args = InitializeMint::try_from_bytes(instruction_data)?; + + // Validates the accounts. + + let (mint_info, rent_sysvar_info) = if rent_sysvar_account { + let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (mint_info, Some(rent_sysvar_info)) + } else { + let [mint_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (mint_info, None) + }; + + let mint = unsafe { Mint::from_bytes_mut(mint_info.borrow_mut_data_unchecked()) }; + + if mint.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } + + // Check rent-exempt status of the mint account. + + let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { + let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + rent.is_exempt(mint_info.lamports(), size_of::()) + } else { + Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) + }; + + if !is_exempt { + return Err(TokenError::NotRentExempt.into()); + } + + // Initialize the mint. + + mint.set_initialized(true); + mint.set_mint_authority(args.mint_authority()); + mint.decimals = args.decimals(); + + if let Some(freeze_authority) = args.freeze_authority() { + mint.set_freeze_authority(freeze_authority); + } + + Ok(()) +} + +/// Instruction data for the `InitializeMint` instruction. +pub struct InitializeMint<'a> { + raw: *const u8, + + _data: PhantomData<&'a [u8]>, +} + +impl InitializeMint<'_> { + #[inline] + pub fn try_from_bytes(bytes: &[u8]) -> Result { + // The minimum expected size of the instruction data. + // - decimals (1 byte) + // - mint_authority (32 bytes) + // - option + freeze_authority (1 byte + 32 bytes) + if bytes.len() < 34 { + return Err(ProgramError::InvalidInstructionData); + } + + Ok(InitializeMint { + raw: bytes.as_ptr(), + _data: PhantomData, + }) + } + + #[inline] + pub fn decimals(&self) -> u8 { + unsafe { *self.raw } + } + + #[inline] + pub fn mint_authority(&self) -> &Pubkey { + unsafe { &*(self.raw.add(1) as *const Pubkey) } + } + + #[inline] + pub fn freeze_authority(&self) -> Option<&Pubkey> { + unsafe { + if *self.raw.add(33) == 0 { + Option::None + } else { + Option::Some(&*(self.raw.add(34) as *const Pubkey)) + } + } + } } diff --git a/p-token/src/processor/initialize_mint2.rs b/p-token/src/processor/initialize_mint2.rs index 5387566..0f1f07d 100644 --- a/p-token/src/processor/initialize_mint2.rs +++ b/p-token/src/processor/initialize_mint2.rs @@ -1,8 +1,11 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; -use super::shared::{self, initialize_mint::InitializeMint}; +use super::initialize_mint::process_initialize_mint; -#[inline(never)] -pub fn process_initialize_mint2(accounts: &[AccountInfo], args: &InitializeMint) -> ProgramResult { - shared::initialize_mint::process_initialize_mint(accounts, args, false) +#[inline(always)] +pub fn process_initialize_mint2( + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + process_initialize_mint(accounts, instruction_data, false) } diff --git a/p-token/src/processor/initialize_multisig.rs b/p-token/src/processor/initialize_multisig.rs index 7fddab5..a5f888b 100644 --- a/p-token/src/processor/initialize_multisig.rs +++ b/p-token/src/processor/initialize_multisig.rs @@ -1,64 +1,15 @@ -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, -}; -use token_interface::{error::TokenError, state::multisig::Multisig}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -#[inline(never)] +use super::shared; + +#[inline(always)] pub fn process_initialize_multisig( accounts: &[AccountInfo], - m: u8, - rent_sysvar_account: bool, + instruction_data: &[u8], ) -> ProgramResult { - let (multisig_info, rent_sysvar_info, remaining) = if rent_sysvar_account { - let [multisig_info, rent_sysvar_info, remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (multisig_info, Some(rent_sysvar_info), remaining) - } else { - let [multisig_info, remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (multisig_info, None, remaining) - }; - - let multisig_info_data_len = multisig_info.data_len(); - - let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { - let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; - rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) - } else { - Rent::get()?.is_exempt(multisig_info.lamports(), multisig_info_data_len) - }; - - if !is_exempt { - return Err(TokenError::NotRentExempt.into()); - } - - let multisig = bytemuck::try_from_bytes_mut::(unsafe { - multisig_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if multisig.is_initialized.into() { - return Err(TokenError::AlreadyInUse.into()); - } - - multisig.m = m; - multisig.n = remaining.len() as u8; - - if !Multisig::is_valid_signer_index(multisig.n as usize) { - return Err(TokenError::InvalidNumberOfProvidedSigners.into()); - } - if !Multisig::is_valid_signer_index(multisig.m as usize) { - return Err(TokenError::InvalidNumberOfRequiredSigners.into()); - } - for (i, signer_info) in remaining.iter().enumerate() { - multisig.signers[i] = *signer_info.key(); - } - multisig.is_initialized = true.into(); + let m = instruction_data + .first() + .ok_or(ProgramError::InvalidInstructionData)?; - Ok(()) + shared::initialize_multisig::process_initialize_multisig(accounts, *m, true) } diff --git a/p-token/src/processor/initialize_multisig2.rs b/p-token/src/processor/initialize_multisig2.rs index 9dfbf96..138a91b 100644 --- a/p-token/src/processor/initialize_multisig2.rs +++ b/p-token/src/processor/initialize_multisig2.rs @@ -1,8 +1,14 @@ -use pinocchio::{account_info::AccountInfo, ProgramResult}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult { - shared::initialize_multisig::process_initialize_multisig(accounts, m, false) +#[inline(always)] +pub fn process_initialize_multisig2( + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + let m = instruction_data + .first() + .ok_or(ProgramError::InvalidInstructionData)?; + shared::initialize_multisig::process_initialize_multisig(accounts, *m, false) } diff --git a/p-token/src/processor/mint_to.rs b/p-token/src/processor/mint_to.rs index 3dadbc1..59db533 100644 --- a/p-token/src/processor/mint_to.rs +++ b/p-token/src/processor/mint_to.rs @@ -1,12 +1,14 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_mint_to( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, -) -> ProgramResult { - shared::mint_to::process_mint_to(program_id, accounts, amount, None) +#[inline(always)] +pub fn process_mint_to(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + let amount = u64::from_le_bytes( + instruction_data + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + shared::mint_to::process_mint_to(accounts, amount, None) } diff --git a/p-token/src/processor/mint_to_checked.rs b/p-token/src/processor/mint_to_checked.rs index 25684d4..6fb3ae9 100644 --- a/p-token/src/processor/mint_to_checked.rs +++ b/p-token/src/processor/mint_to_checked.rs @@ -1,47 +1,20 @@ -use std::marker::PhantomData; - -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_mint_to_checked( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, - decimals: u8, -) -> ProgramResult { - shared::mint_to::process_mint_to(program_id, accounts, amount, Some(decimals)) -} - -pub struct MintToChecked<'a> { - raw: *const u8, - - _data: PhantomData<&'a [u8]>, -} - -impl MintToChecked<'_> { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != 9 { - return Err(ProgramError::InvalidInstructionData); - } - - Ok(MintToChecked { - raw: bytes.as_ptr(), - _data: PhantomData, - }) - } - - pub fn amount(&self) -> u64 { - unsafe { - let amount = self.raw as *const u64; - amount.read_unaligned() - } - } - - pub fn decimals(&self) -> u8 { - unsafe { *self.raw.add(8) } - } +#[inline(always)] +pub fn process_mint_to_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + + let amount = u64::from_le_bytes( + amount + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + shared::mint_to::process_mint_to( + accounts, + amount, + Some(*decimals.first().ok_or(ProgramError::InvalidAccountData)?), + ) } diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 9527cc7..a8dd6c4 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -34,6 +34,32 @@ pub mod ui_amount_to_amount; // Shared processors. pub mod shared; +pub use amount_to_ui_amount::process_amount_to_ui_amount; +pub use approve::process_approve; +pub use approve_checked::process_approve_checked; +pub use burn::process_burn; +pub use burn_checked::process_burn_checked; +pub use close_account::process_close_account; +pub use freeze_account::process_freeze_account; +pub use get_account_data_size::process_get_account_data_size; +pub use initialize_account::process_initialize_account; +pub use initialize_account2::process_initialize_account2; +pub use initialize_account3::process_initialize_account3; +pub use initialize_immutable_owner::process_initialize_immutable_owner; +pub use initialize_mint::process_initialize_mint; +pub use initialize_mint2::process_initialize_mint2; +pub use initialize_multisig::process_initialize_multisig; +pub use initialize_multisig2::process_initialize_multisig2; +pub use mint_to::process_mint_to; +pub use mint_to_checked::process_mint_to_checked; +pub use revoke::process_revoke; +pub use set_authority::process_set_authority; +pub use sync_native::process_sync_native; +pub use thaw_account::process_thaw_account; +pub use transfer::process_transfer; +pub use transfer_checked::process_transfer_checked; +pub use ui_amount_to_amount::process_ui_amount_to_amount; + /// Incinerator address. const INCINERATOR_ID: Pubkey = pinocchio_pubkey::pubkey!("1nc1nerator11111111111111111111111111111111"); @@ -42,14 +68,14 @@ const INCINERATOR_ID: Pubkey = const SYSTEM_PROGRAM_ID: Pubkey = pinocchio_pubkey::pubkey!("11111111111111111111111111111111"); #[inline(always)] -pub fn is_owned_by_system_program_or_incinerator(owner: &Pubkey) -> bool { - SYSTEM_PROGRAM_ID == *owner || INCINERATOR_ID == *owner +fn is_owned_by_system_program_or_incinerator(owner: &Pubkey) -> bool { + &SYSTEM_PROGRAM_ID == owner || &INCINERATOR_ID == owner } /// Checks that the account is owned by the expected program. #[inline(always)] -pub fn check_account_owner(program_id: &Pubkey, account_info: &AccountInfo) -> ProgramResult { - if program_id != account_info.owner() { +fn check_account_owner(account_info: &AccountInfo) -> ProgramResult { + if &crate::ID != account_info.owner() { Err(ProgramError::IncorrectProgramId) } else { Ok(()) @@ -58,8 +84,7 @@ pub fn check_account_owner(program_id: &Pubkey, account_info: &AccountInfo) -> P /// Validates owner(s) are present #[inline(always)] -pub fn validate_owner( - program_id: &Pubkey, +fn validate_owner( expected_owner: &Pubkey, owner_account_info: &AccountInfo, signers: &[AccountInfo], @@ -68,9 +93,8 @@ pub fn validate_owner( return Err(TokenError::OwnerMismatch.into()); } - if owner_account_info.data_len() == Multisig::LEN && program_id != owner_account_info.owner() { - let multisig_data = owner_account_info.try_borrow_data()?; - let multisig = bytemuck::from_bytes::(&multisig_data); + if owner_account_info.data_len() == Multisig::LEN && &crate::ID != owner_account_info.owner() { + let multisig = unsafe { Multisig::from_bytes(owner_account_info.borrow_data_unchecked()) }; let mut num_signers = 0; let mut matched = [false; MAX_SIGNERS]; @@ -99,7 +123,7 @@ pub fn validate_owner( /// Convert a raw amount to its UI representation using the given decimals field /// Excess zeroes or unneeded decimal point are trimmed. #[inline(always)] -pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { +fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { let mut s = amount_to_ui_amount_string(amount, decimals); if decimals > 0 { let zeros_trimmed = s.trim_end_matches('0'); @@ -111,7 +135,7 @@ pub fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { /// Convert a raw amount to its UI representation (using the decimals field /// defined in its mint) #[inline(always)] -pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { +fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { let decimals = decimals as usize; if decimals > 0 { // Left-pad zeros to decimals + 1, so we at least have an integer zero @@ -126,7 +150,7 @@ pub fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { /// Try to convert a UI representation of a token amount to its raw amount using /// the given decimals field -pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { +fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { let decimals = decimals as usize; let mut parts = ui_amount.split('.'); // splitting a string, even an empty one, will always yield an iterator of at diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs index c77d8b2..4ed5016 100644 --- a/p-token/src/processor/revoke.rs +++ b/p-token/src/processor/revoke.rs @@ -1,29 +1,25 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{error::TokenError, state::account::Account}; use super::validate_owner; -#[inline(never)] -pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { +#[inline(always)] +pub fn process_revoke(accounts: &[AccountInfo], _instruction_data: &[u8]) -> ProgramResult { let [source_account_info, owner_info, remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - let source_account = bytemuck::try_from_bytes_mut::(unsafe { - source_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let source_account = + unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } - validate_owner(program_id, &source_account.owner, owner_info, remaning)?; + validate_owner(&source_account.owner, owner_info, remaning)?; - source_account.delegate.clear(); - source_account.delegated_amount = 0.into(); + source_account.clear_delegate(); + source_account.set_delegated_amount(0); Ok(()) } diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index f0ed452..4661342 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -1,33 +1,33 @@ +use core::marker::PhantomData; + use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::{Pubkey, PUBKEY_BYTES}, - ProgramResult, + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; use token_interface::{ error::TokenError, instruction::AuthorityType, - state::{account::Account, mint::Mint, PodCOption}, + state::{account::Account, mint::Mint}, }; use super::validate_owner; -#[inline(never)] -pub fn process_set_authority( - program_id: &Pubkey, - accounts: &[AccountInfo], - authority_type: AuthorityType, - new_authority: Option<&Pubkey>, -) -> ProgramResult { +#[inline(always)] +pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + // Validates the instruction data. + + let args = SetAuthority::try_from_bytes(instruction_data)?; + + let authority_type = args.authority_type()?; + let new_authority = args.new_authority(); + + // Validates the accounts. + let [account_info, authority_info, remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; if account_info.data_len() == Account::LEN { - let account = bytemuck::try_from_bytes_mut::(unsafe { - account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let account = unsafe { Account::from_bytes_mut(account_info.borrow_mut_data_unchecked()) }; if account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -35,7 +35,7 @@ pub fn process_set_authority( match authority_type { AuthorityType::AccountOwner => { - validate_owner(program_id, &account.owner, authority_info, remaning)?; + validate_owner(&account.owner, authority_info, remaning)?; if let Some(authority) = new_authority { account.owner = *authority; @@ -43,50 +43,58 @@ pub fn process_set_authority( return Err(TokenError::InvalidInstruction.into()); } - account.delegate.clear(); - account.delegated_amount = 0.into(); + account.clear_delegate(); + account.set_delegated_amount(0); - if account.is_native.is_some() { - account.close_authority.clear(); + if account.is_native() { + account.clear_close_authority(); } } AuthorityType::CloseAccount => { - let authority = account.close_authority.as_ref().unwrap_or(&account.owner); - validate_owner(program_id, authority, authority_info, remaning)?; - account.close_authority = PodCOption::from(new_authority.copied()); + let authority = account.close_authority().unwrap_or(&account.owner); + validate_owner(authority, authority_info, remaning)?; + + if let Some(authority) = new_authority { + account.set_close_authority(authority); + } else { + account.clear_close_authority(); + } } _ => { return Err(TokenError::AuthorityTypeNotSupported.into()); } } } else if account_info.data_len() == Mint::LEN { - let mint = bytemuck::try_from_bytes_mut::(unsafe { - account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let mint = unsafe { Mint::from_bytes_mut(account_info.borrow_mut_data_unchecked()) }; match authority_type { AuthorityType::MintTokens => { // Once a mint's supply is fixed, it cannot be undone by setting a new - // mint_authority - let mint_authority = mint - .mint_authority - .as_ref() - .ok_or(TokenError::FixedSupply)?; - - validate_owner(program_id, mint_authority, authority_info, remaning)?; - mint.mint_authority = PodCOption::from(new_authority.copied()); + // mint_authority. + let mint_authority = mint.mint_authority().ok_or(TokenError::FixedSupply)?; + + validate_owner(mint_authority, authority_info, remaning)?; + + if let Some(authority) = new_authority { + mint.set_mint_authority(authority); + } else { + mint.clear_mint_authority(); + } } AuthorityType::FreezeAccount => { // Once a mint's freeze authority is disabled, it cannot be re-enabled by - // setting a new freeze_authority + // setting a new freeze_authority. let freeze_authority = mint - .freeze_authority - .as_ref() + .freeze_authority() .ok_or(TokenError::MintCannotFreeze)?; - validate_owner(program_id, freeze_authority, authority_info, remaning)?; - mint.freeze_authority = PodCOption::from(new_authority.copied()); + validate_owner(freeze_authority, authority_info, remaning)?; + + if let Some(authority) = new_authority { + mint.set_freeze_authority(authority); + } else { + mint.clear_freeze_authority(); + } } _ => { return Err(TokenError::AuthorityTypeNotSupported.into()); @@ -99,35 +107,41 @@ pub fn process_set_authority( Ok(()) } -/// Instruction data for the `InitializeMint` instruction. -pub struct SetAuthority<'a> { - pub authority_type: AuthorityType, +struct SetAuthority<'a> { + raw: *const u8, - /// New authority. - pub new_authority: Option<&'a Pubkey>, + _data: PhantomData<&'a [u8]>, } -impl<'a> SetAuthority<'a> { - pub fn try_from_bytes(data: &'a [u8]) -> Result { - // We expect the data to be at least the size of the u8 (authority_type) - // plus one byte for the authority option. - if data.len() <= 2 { +impl SetAuthority<'_> { + #[inline(always)] + pub fn try_from_bytes(bytes: &[u8]) -> Result { + // The minimum expected size of the instruction data. + // - authority_type (1 byte) + // - option + new_authority (1 byte + 32 bytes) + if bytes.len() < 2 { return Err(ProgramError::InvalidInstructionData); } - let (authority_type, remaining) = data.split_at(1); + Ok(SetAuthority { + raw: bytes.as_ptr(), + _data: PhantomData, + }) + } - let new_authority = match remaining.split_first() { - Some((&0, _)) => None, - Some((&1, pubkey)) if pubkey.len() == PUBKEY_BYTES => { - Some(bytemuck::from_bytes::(pubkey)) - } - _ => return Err(ProgramError::InvalidInstructionData), - }; + #[inline(always)] + pub fn authority_type(&self) -> Result { + unsafe { AuthorityType::from(*self.raw) } + } - Ok(Self { - authority_type: AuthorityType::from(authority_type[0]), - new_authority, - }) + #[inline(always)] + pub fn new_authority(&self) -> Option<&Pubkey> { + unsafe { + if *self.raw.add(1) == 0 { + Option::None + } else { + Option::Some(&*(self.raw.add(2) as *const Pubkey)) + } + } } } diff --git a/p-token/src/processor/shared/approve.rs b/p-token/src/processor/shared/approve.rs index 303d943..5715a12 100644 --- a/p-token/src/processor/shared/approve.rs +++ b/p-token/src/processor/shared/approve.rs @@ -1,20 +1,20 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - state::{account::Account, mint::Mint, PodCOption}, + state::{account::Account, mint::Mint}, }; use crate::processor::validate_owner; #[inline(always)] pub fn process_approve( - program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, expected_decimals: Option, ) -> ProgramResult { + // Accounts expected depend on whether we have the mint `decimals` or not; when we have the + // mint `decimals`, we expect the mint account to be present. + let (source_account_info, expected_mint_info, delegate_info, owner_info, remaining) = if let Some(expected_decimals) = expected_decimals { let [source_account_info, expected_mint_info, delegate_info, owner_info, remaning @ ..] = @@ -43,10 +43,10 @@ pub fn process_approve( ) }; - let source_account = bytemuck::try_from_bytes_mut::(unsafe { - source_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + // Validates source account. + + let source_account = + unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -57,18 +57,19 @@ pub fn process_approve( return Err(TokenError::MintMismatch.into()); } - let mint = bytemuck::try_from_bytes::(unsafe { mint_info.borrow_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; if expected_decimals != mint.decimals { return Err(TokenError::MintDecimalsMismatch.into()); } } - validate_owner(program_id, &source_account.owner, owner_info, remaining)?; + validate_owner(&source_account.owner, owner_info, remaining)?; + + // Sets the delegate and delegated amount. - source_account.delegate = PodCOption::some(*delegate_info.key()); - source_account.delegated_amount = amount.into(); + source_account.set_delegate(delegate_info.key()); + source_account.set_delegated_amount(amount); Ok(()) } diff --git a/p-token/src/processor/shared/burn.rs b/p-token/src/processor/shared/burn.rs index c46d0e3..d23872f 100644 --- a/p-token/src/processor/shared/burn.rs +++ b/p-token/src/processor/shared/burn.rs @@ -1,6 +1,4 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, state::{account::Account, mint::Mint}, @@ -12,7 +10,6 @@ use crate::processor::{ #[inline(always)] pub fn process_burn( - program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, expected_decimals: Option, @@ -21,29 +18,24 @@ pub fn process_burn( return Err(ProgramError::NotEnoughAccountKeys); }; - // Safety: There are no conflicting borrows – the source account is only borrowed once. - let source_account = bytemuck::try_from_bytes_mut::(unsafe { - source_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let source_account = + unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } - if source_account.is_native.is_some() { + if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } // Ensure the source account has the sufficient amount. This is done before // the value is updated on the account. - let updated_source_amount = u64::from(source_account.amount) + let updated_source_amount = source_account + .amount() .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; - // Safety: There are no conflicting borrows – the mint account is only borrowed once. - let mint = - bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let mint = unsafe { Mint::from_bytes_mut(mint_info.borrow_mut_data_unchecked()) }; if mint_info.key() != &source_account.mint { return Err(TokenError::MintMismatch.into()); @@ -56,36 +48,40 @@ pub fn process_burn( } if !is_owned_by_system_program_or_incinerator(&source_account.owner) { - match source_account.delegate.as_ref() { + match source_account.delegate() { Some(delegate) if authority_info.key() == delegate => { - validate_owner(program_id, delegate, authority_info, remaining)?; + validate_owner(delegate, authority_info, remaining)?; - let delegated_amount = u64::from(source_account.delegated_amount) + let delegated_amount = source_account + .delegated_amount() .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; - source_account.delegated_amount = delegated_amount.into(); + source_account.set_delegated_amount(delegated_amount); if delegated_amount == 0 { - source_account.delegate.clear(); + source_account.clear_delegate(); } } _ => { - validate_owner(program_id, &source_account.owner, authority_info, remaining)?; + validate_owner(&source_account.owner, authority_info, remaining)?; } } } - if amount == 0 { - check_account_owner(program_id, source_account_info)?; - check_account_owner(program_id, mint_info)?; - } + // Updates the source account and mint supply. - source_account.amount = updated_source_amount.into(); + if amount == 0 { + check_account_owner(source_account_info)?; + check_account_owner(mint_info)?; + } else { + source_account.set_amount(updated_source_amount); - let mint_supply = u64::from(mint.supply) - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; - mint.supply = mint_supply.into(); + let mint_supply = mint + .supply() + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + mint.set_supply(mint_supply); + } Ok(()) } diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index 8176ed3..fc66467 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -1,3 +1,4 @@ +use core::mem::size_of; use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, @@ -5,26 +6,22 @@ use pinocchio::{ sysvars::{rent::Rent, Sysvar}, ProgramResult, }; -use std::mem::size_of; use token_interface::{ error::TokenError, native_mint::is_native_mint, - state::{ - account::{Account, AccountState}, - mint::Mint, - PodCOption, - }, + state::{account::Account, account_state::AccountState, mint::Mint}, }; use crate::processor::check_account_owner; #[inline(always)] pub fn process_initialize_account( - program_id: &Pubkey, accounts: &[AccountInfo], owner: Option<&Pubkey>, rent_sysvar_account: bool, ) -> ProgramResult { + // Accounts expected depend on whether we have the `rent_sysvar` account or not. + let (new_account_info, mint_info, owner, remaning) = if let Some(owner) = owner { let [new_account_info, mint_info, remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -51,9 +48,9 @@ pub fn process_initialize_account( return Err(TokenError::NotRentExempt.into()); } - let account_data = unsafe { new_account_info.borrow_mut_data_unchecked() }; - let account = bytemuck::try_from_bytes_mut::(account_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; + // Initialize the account. + + let account = unsafe { Account::from_bytes_mut(new_account_info.borrow_mut_data_unchecked()) }; if account.is_initialized() { return Err(TokenError::AlreadyInUse.into()); @@ -62,40 +59,33 @@ pub fn process_initialize_account( let is_native_mint = is_native_mint(mint_info.key()); if !is_native_mint { - check_account_owner(program_id, mint_info)?; + check_account_owner(mint_info)?; - let mint_data = unsafe { mint_info.borrow_data_unchecked() }; - let mint = bytemuck::try_from_bytes::(mint_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; - if !bool::from(mint.is_initialized) { + if !mint.is_initialized() { return Err(TokenError::InvalidMint.into()); } } + account.state = AccountState::Initialized; account.mint = *mint_info.key(); account.owner = *owner; - account.close_authority.clear(); - account.delegate.clear(); - account.delegated_amount = 0u64.into(); - account.state = AccountState::Initialized as u8; if is_native_mint { let rent = Rent::get()?; let rent_exempt_reserve = rent.minimum_balance(size_of::()); - account.is_native = PodCOption::from(Some(rent_exempt_reserve.into())); + account.set_native(true); unsafe { - account.amount = new_account_info - .borrow_lamports_unchecked() - .checked_sub(rent_exempt_reserve) - .ok_or(TokenError::Overflow)? - .into() + account.set_amount( + new_account_info + .borrow_lamports_unchecked() + .checked_sub(rent_exempt_reserve) + .ok_or(TokenError::Overflow)?, + ); } - } else { - account.is_native.clear(); - account.amount = 0u64.into(); - }; + } Ok(()) } diff --git a/p-token/src/processor/shared/initialize_mint.rs b/p-token/src/processor/shared/initialize_mint.rs deleted file mode 100644 index 845b64b..0000000 --- a/p-token/src/processor/shared/initialize_mint.rs +++ /dev/null @@ -1,106 +0,0 @@ -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::Pubkey, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, -}; -use std::{marker::PhantomData, mem::size_of}; -use token_interface::{ - error::TokenError, - state::{mint::Mint, PodCOption}, -}; - -#[inline(always)] -pub fn process_initialize_mint( - accounts: &[AccountInfo], - args: &InitializeMint, - rent_sysvar_account: bool, -) -> ProgramResult { - let (mint_info, rent_sysvar_info) = if rent_sysvar_account { - let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (mint_info, Some(rent_sysvar_info)) - } else { - let [mint_info, _remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (mint_info, None) - }; - - let mint = - bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; - - if mint.is_initialized.into() { - return Err(TokenError::AlreadyInUse.into()); - } - - // Check rent-exempt status of the mint account. - - let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { - let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; - rent.is_exempt(mint_info.lamports(), size_of::()) - } else { - Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) - }; - - if !is_exempt { - return Err(TokenError::NotRentExempt.into()); - } - - // Initialize the mint. - - mint.mint_authority = PodCOption::from(Some(*args.mint_authority())); - mint.decimals = args.decimals(); - mint.is_initialized = true.into(); - - if let Some(freeze_authority) = args.freeze_authority() { - mint.freeze_authority = PodCOption::from(Some(*freeze_authority)); - } - - Ok(()) -} - -/// Instruction data for the `InitializeMint` instruction. -pub struct InitializeMint<'a> { - raw: *const u8, - - _data: PhantomData<&'a [u8]>, -} - -impl InitializeMint<'_> { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - // The minimum expected size of the instruction data. - // - decimals (1 byte) - // - mint_authority (32 bytes) - // - option + freeze_authority (1 byte + 32 bytes) - if bytes.len() < 34 { - return Err(ProgramError::InvalidInstructionData); - } - - Ok(InitializeMint { - raw: bytes.as_ptr(), - _data: PhantomData, - }) - } - - pub fn decimals(&self) -> u8 { - unsafe { *self.raw } - } - - pub fn mint_authority(&self) -> &Pubkey { - unsafe { &*(self.raw.add(1) as *const Pubkey) } - } - - pub fn freeze_authority(&self) -> Option<&Pubkey> { - unsafe { - if *self.raw.add(33) == 0 { - Option::None - } else { - Option::Some(&*(self.raw.add(34) as *const Pubkey)) - } - } - } -} diff --git a/p-token/src/processor/shared/initialize_multisig.rs b/p-token/src/processor/shared/initialize_multisig.rs index 8db95f1..cae5084 100644 --- a/p-token/src/processor/shared/initialize_multisig.rs +++ b/p-token/src/processor/shared/initialize_multisig.rs @@ -12,6 +12,8 @@ pub fn process_initialize_multisig( m: u8, rent_sysvar_account: bool, ) -> ProgramResult { + // Accounts expected depend on whether we have the `rent_sysvar` account or not. + let (multisig_info, rent_sysvar_info, remaining) = if rent_sysvar_account { let [multisig_info, rent_sysvar_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -37,15 +39,14 @@ pub fn process_initialize_multisig( return Err(TokenError::NotRentExempt.into()); } - let multisig = bytemuck::try_from_bytes_mut::(unsafe { - multisig_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let multisig = unsafe { Multisig::from_bytes_mut(multisig_info.borrow_mut_data_unchecked()) }; - if multisig.is_initialized.into() { + if multisig.is_initialized() { return Err(TokenError::AlreadyInUse.into()); } + // Initialize the multisig account. + multisig.m = m; multisig.n = remaining.len() as u8; @@ -55,10 +56,12 @@ pub fn process_initialize_multisig( if !Multisig::is_valid_signer_index(multisig.m as usize) { return Err(TokenError::InvalidNumberOfRequiredSigners.into()); } + for (i, signer_info) in remaining.iter().enumerate() { multisig.signers[i] = *signer_info.key(); } - multisig.is_initialized = true.into(); + + multisig.set_initialized(true); Ok(()) } diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs index 62ca9d7..cc891bd 100644 --- a/p-token/src/processor/shared/mint_to.rs +++ b/p-token/src/processor/shared/mint_to.rs @@ -1,9 +1,6 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - native_mint::is_native_mint, state::{account::Account, mint::Mint}, }; @@ -11,7 +8,6 @@ use crate::processor::{check_account_owner, validate_owner}; #[inline(always)] pub fn process_mint_to( - program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, expected_decimals: Option, @@ -20,17 +16,16 @@ pub fn process_mint_to( return Err(ProgramError::NotEnoughAccountKeys); }; - // destination account + // Validates the destination account. - let account_data = unsafe { destination_account_info.borrow_mut_data_unchecked() }; - let destination_account = bytemuck::try_from_bytes_mut::(account_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let destination_account = + unsafe { Account::from_bytes_mut(destination_account_info.borrow_mut_data_unchecked()) }; if destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } - if is_native_mint(mint_info.key()) { + if destination_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } @@ -38,9 +33,7 @@ pub fn process_mint_to( return Err(TokenError::MintMismatch.into()); } - let mint_data = unsafe { mint_info.borrow_mut_data_unchecked() }; - let mint = bytemuck::try_from_bytes_mut::(mint_data) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let mint = unsafe { Mint::from_bytes_mut(mint_info.borrow_mut_data_unchecked()) }; if let Some(expected_decimals) = expected_decimals { if expected_decimals != mint.decimals { @@ -48,25 +41,27 @@ pub fn process_mint_to( } } - match mint.mint_authority.get() { - Some(mint_authority) => validate_owner(program_id, &mint_authority, owner_info, remaining)?, + match mint.mint_authority() { + Some(mint_authority) => validate_owner(mint_authority, owner_info, remaining)?, None => return Err(TokenError::FixedSupply.into()), } if amount == 0 { - check_account_owner(program_id, mint_info)?; - check_account_owner(program_id, destination_account_info)?; + check_account_owner(mint_info)?; + check_account_owner(destination_account_info)?; } - let destination_amount = u64::from(destination_account.amount) + let destination_amount = destination_account + .amount() .checked_add(amount) .ok_or(ProgramError::InvalidAccountData)?; - destination_account.amount = destination_amount.into(); + destination_account.set_amount(destination_amount); - let mint_supply = u64::from(mint.supply) + let mint_supply = mint + .supply() .checked_add(amount) .ok_or(ProgramError::InvalidAccountData)?; - mint.supply = mint_supply.into(); + mint.set_supply(mint_supply); Ok(()) } diff --git a/p-token/src/processor/shared/mod.rs b/p-token/src/processor/shared/mod.rs index 634ccab..e55f129 100644 --- a/p-token/src/processor/shared/mod.rs +++ b/p-token/src/processor/shared/mod.rs @@ -1,7 +1,11 @@ +//! Shared processor functions. +//! +//! This module contains the shared processor functions that are used by +//! the multiple instruction processors. + pub mod approve; pub mod burn; pub mod initialize_account; -pub mod initialize_mint; pub mod initialize_multisig; pub mod mint_to; pub mod toggle_account_state; diff --git a/p-token/src/processor/shared/toggle_account_state.rs b/p-token/src/processor/shared/toggle_account_state.rs index e55ea63..f52b619 100644 --- a/p-token/src/processor/shared/toggle_account_state.rs +++ b/p-token/src/processor/shared/toggle_account_state.rs @@ -1,54 +1,42 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - state::{ - account::{Account, AccountState}, - mint::Mint, - }, + state::{account::Account, account_state::AccountState, mint::Mint}, }; use crate::processor::validate_owner; #[inline(always)] -pub fn process_toggle_account_state( - program_id: &Pubkey, - accounts: &[AccountInfo], - freeze: bool, -) -> ProgramResult { +pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> ProgramResult { let [source_account_info, mint_info, authority_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - let source_account = bytemuck::try_from_bytes_mut::(unsafe { - source_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let source_account = + unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { return Err(TokenError::InvalidState.into()); } - if source_account.is_native.is_some() { + if source_account.is_native() { return Err(TokenError::NativeNotSupported.into()); } if mint_info.key() != &source_account.mint { return Err(TokenError::MintMismatch.into()); } - let mint = bytemuck::try_from_bytes::(unsafe { mint_info.borrow_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; - match mint.freeze_authority.as_ref() { - Option::Some(authority) => validate_owner(program_id, authority, authority_info, remaining), - Option::None => Err(TokenError::MintCannotFreeze.into()), + match mint.freeze_authority() { + Some(authority) => validate_owner(authority, authority_info, remaining), + None => Err(TokenError::MintCannotFreeze.into()), }?; source_account.state = if freeze { AccountState::Frozen } else { AccountState::Initialized - } as u8; + }; Ok(()) } diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index 766011b..5624076 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -1,22 +1,18 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - native_mint::is_native_mint, - state::{account::Account, mint::Mint, PodCOption}, + state::{account::Account, mint::Mint}, }; use crate::processor::{check_account_owner, validate_owner}; #[inline(always)] pub fn process_transfer( - program_id: &Pubkey, accounts: &[AccountInfo], amount: u64, expected_decimals: Option, ) -> ProgramResult { - // Accounts expected depends on whether we have the mint `decimals` or not; when we have the + // Accounts expected depend on whether we have the mint `decimals` or not; when we have the // mint `decimals`, we expect the mint account to be present. let ( @@ -55,24 +51,21 @@ pub fn process_transfer( // Validates source and destination accounts. - let source_account = bytemuck::try_from_bytes_mut::(unsafe { - source_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let source_account = + unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; - let destination_account = bytemuck::try_from_bytes_mut::(unsafe { - destination_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let destination_account = + unsafe { Account::from_bytes_mut(destination_account_info.borrow_mut_data_unchecked()) }; if source_account.is_frozen() || destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); } - // FEBO: Implicitly validates that the account has enough tokens by calculating the - // remaining amount. The amount is only updated on the account if the transfer + // Implicitly validates that the account has enough tokens by calculating the + // remaining amount - the amount is only updated on the account if the transfer // is successful. - let remaining_amount = u64::from(source_account.amount) + let remaining_amount = source_account + .amount() .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; @@ -87,72 +80,65 @@ pub fn process_transfer( return Err(TokenError::MintMismatch.into()); } - let mint = - bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; if decimals != mint.decimals { return Err(TokenError::MintDecimalsMismatch.into()); } } - let self_transfer = source_account_info.key() == destination_account_info.key(); + // Comparing whether the `AccountInfo`s "point" to the same acount - this + // is a faster comparison since it just checks the internal raw pointer. + let self_transfer = source_account_info == destination_account_info; // Validates the authority (delegate or owner). - if source_account.delegate.as_ref() == Some(authority_info.key()) { - validate_owner(program_id, authority_info.key(), authority_info, remaning)?; + if source_account.delegate() == Some(authority_info.key()) { + validate_owner(authority_info.key(), authority_info, remaning)?; - let delegated_amount = u64::from(source_account.delegated_amount) + let delegated_amount = source_account + .delegated_amount() .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; if !self_transfer { - source_account.delegated_amount = delegated_amount.into(); + source_account.set_delegated_amount(delegated_amount); if delegated_amount == 0 { - source_account.delegate = PodCOption::from(None); + source_account.clear_delegate(); } } } else { - validate_owner(program_id, &source_account.owner, authority_info, remaning)?; + validate_owner(&source_account.owner, authority_info, remaning)?; } if self_transfer || amount == 0 { - check_account_owner(program_id, source_account_info)?; - check_account_owner(program_id, destination_account_info)?; - - // No need to move tokens around. - return Ok(()); - } + // Validates the token accounts owner since we are not writing + // to these account. + check_account_owner(source_account_info)?; + check_account_owner(destination_account_info)?; - // FEBO: This was moved to the if statement above since we can skip the amount - // manipulation if it is a self-transfer or the amount is zero. - // - // This check MUST occur just before the amounts are manipulated - // to ensure self-transfers are fully validated - /* - if self_transfer { return Ok(()); } - */ // Moves the tokens. - source_account.amount = remaining_amount.into(); + source_account.set_amount(remaining_amount); - let destination_amount = u64::from(destination_account.amount) + let destination_amount = destination_account + .amount() .checked_add(amount) .ok_or(TokenError::Overflow)?; - destination_account.amount = destination_amount.into(); + destination_account.set_amount(destination_amount); - if is_native_mint(&source_account.mint) { - let mut source_lamports = source_account_info.try_borrow_mut_lamports()?; + if source_account.is_native() { + let source_lamports = unsafe { source_account_info.borrow_mut_lamports_unchecked() }; *source_lamports = source_lamports .checked_sub(amount) .ok_or(TokenError::Overflow)?; - let mut destination_lamports = destination_account_info.try_borrow_mut_lamports()?; + let destination_lamports = + unsafe { destination_account_info.borrow_mut_lamports_unchecked() }; *destination_lamports = destination_lamports .checked_add(amount) .ok_or(TokenError::Overflow)?; diff --git a/p-token/src/processor/sync_native.rs b/p-token/src/processor/sync_native.rs index 25b2029..fd90f2b 100644 --- a/p-token/src/processor/sync_native.rs +++ b/p-token/src/processor/sync_native.rs @@ -1,31 +1,27 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{error::TokenError, state::account::Account}; use super::check_account_owner; -#[inline(never)] -pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { +#[inline(always)] +pub fn process_sync_native(accounts: &[AccountInfo]) -> ProgramResult { let native_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; - check_account_owner(program_id, native_account_info)?; + check_account_owner(native_account_info)?; - let native_account = bytemuck::try_from_bytes_mut::(unsafe { - native_account_info.borrow_mut_data_unchecked() - }) - .map_err(|_error| ProgramError::InvalidAccountData)?; + let native_account = + unsafe { Account::from_bytes_mut(native_account_info.borrow_mut_data_unchecked()) }; - if let Option::Some(rent_exempt_reserve) = native_account.is_native.get() { + if let Option::Some(rent_exempt_reserve) = native_account.native_amount() { let new_amount = native_account_info .lamports() - .checked_sub(u64::from(rent_exempt_reserve)) + .checked_sub(rent_exempt_reserve) .ok_or(TokenError::Overflow)?; - if new_amount < native_account.amount.into() { + if new_amount < native_account.amount() { return Err(TokenError::InvalidState.into()); } - native_account.amount = new_amount.into(); + native_account.set_amount(new_amount); } else { return Err(TokenError::NonNativeNotSupported.into()); } diff --git a/p-token/src/processor/thaw_account.rs b/p-token/src/processor/thaw_account.rs index 00ea088..924d3b6 100644 --- a/p-token/src/processor/thaw_account.rs +++ b/p-token/src/processor/thaw_account.rs @@ -1,8 +1,8 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{account_info::AccountInfo, ProgramResult}; use super::shared::toggle_account_state::process_toggle_account_state; -#[inline(never)] -pub fn process_thaw_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { - process_toggle_account_state(program_id, accounts, false) +#[inline(always)] +pub fn process_thaw_account(accounts: &[AccountInfo]) -> ProgramResult { + process_toggle_account_state(accounts, false) } diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs index 254134b..52af330 100644 --- a/p-token/src/processor/transfer.rs +++ b/p-token/src/processor/transfer.rs @@ -1,12 +1,14 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] -pub fn process_transfer( - program_id: &Pubkey, - accounts: &[AccountInfo], - amount: u64, -) -> ProgramResult { - shared::transfer::process_transfer(program_id, accounts, amount, None) +#[inline(always)] +pub fn process_transfer(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + let amount = u64::from_le_bytes( + instruction_data + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + shared::transfer::process_transfer(accounts, amount, None) } diff --git a/p-token/src/processor/transfer_checked.rs b/p-token/src/processor/transfer_checked.rs index 1ebcdcd..4c23ee5 100644 --- a/p-token/src/processor/transfer_checked.rs +++ b/p-token/src/processor/transfer_checked.rs @@ -1,47 +1,26 @@ -use std::marker::PhantomData; - -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use super::shared; -#[inline(never)] +#[inline(always)] pub fn process_transfer_checked( - program_id: &Pubkey, accounts: &[AccountInfo], - amount: u64, - decimals: u8, + instruction_data: &[u8], ) -> ProgramResult { - shared::transfer::process_transfer(program_id, accounts, amount, Some(decimals)) -} - -pub struct TransferChecked<'a> { - raw: *const u8, - - _data: PhantomData<&'a [u8]>, -} - -impl TransferChecked<'_> { - pub fn try_from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != 9 { - return Err(ProgramError::InvalidInstructionData); - } - - Ok(TransferChecked { - raw: bytes.as_ptr(), - _data: PhantomData, - }) - } - - pub fn amount(&self) -> u64 { - unsafe { - let amount = self.raw as *const u64; - amount.read_unaligned() - } - } - - pub fn decimals(&self) -> u8 { - unsafe { *self.raw.add(8) } - } + let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + let amount = u64::from_le_bytes( + amount + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ); + + shared::transfer::process_transfer( + accounts, + amount, + Some( + *decimals + .first() + .ok_or(ProgramError::InvalidInstructionData)?, + ), + ) } diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index 4f3dbca..5eb0bd7 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -1,23 +1,22 @@ use pinocchio::{ - account_info::AccountInfo, program::set_return_data, program_error::ProgramError, - pubkey::Pubkey, ProgramResult, + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; -use token_interface::{error::TokenError, state::mint::Mint}; +use token_interface::state::mint::Mint; use super::{check_account_owner, try_ui_amount_into_amount}; -#[inline(never)] +#[inline(always)] pub fn process_ui_amount_to_amount( - program_id: &Pubkey, accounts: &[AccountInfo], - ui_amount: &str, + instruction_data: &[u8], ) -> ProgramResult { + let ui_amount = core::str::from_utf8(instruction_data) + .map_err(|_error| ProgramError::InvalidInstructionData)?; + let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; - check_account_owner(program_id, mint_info)?; + check_account_owner(mint_info)?; - let mint = - bytemuck::try_from_bytes_mut::(unsafe { mint_info.borrow_mut_data_unchecked() }) - .map_err(|_error| TokenError::InvalidMint)?; + let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; let amount = try_ui_amount_into_amount(ui_amount.to_string(), mint.decimals)?; set_return_data(&amount.to_le_bytes()); From 14925dc134caae72770472eda786613e4fce89cd Mon Sep 17 00:00:00 2001 From: febo Date: Sun, 24 Nov 2024 11:45:39 +0000 Subject: [PATCH 282/335] Typo in comment --- p-token/src/processor/shared/transfer.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index 5624076..d3818b3 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -87,8 +87,9 @@ pub fn process_transfer( } } - // Comparing whether the `AccountInfo`s "point" to the same acount - this - // is a faster comparison since it just checks the internal raw pointer. + // Comparing whether the AccountInfo's "point" to the same account or + // not - this is a faster comparison since it just checks the internal + // raw pointer. let self_transfer = source_account_info == destination_account_info; // Validates the authority (delegate or owner). From 19cd097400414ad0d683341008529440bcf38910 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 25 Nov 2024 15:38:11 +0000 Subject: [PATCH 283/335] Update pinocchio dependency --- p-token/src/processor/close_account.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs index 31432e7..8f5e79c 100644 --- a/p-token/src/processor/close_account.rs +++ b/p-token/src/processor/close_account.rs @@ -33,12 +33,12 @@ pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { let destination_starting_lamports = destination_account_info.lamports(); unsafe { - // Moves the lamports to the destination account and closes the source account. + // Moves the lamports to the destination account. *destination_account_info.borrow_mut_lamports_unchecked() = destination_starting_lamports .checked_add(source_account_info.lamports()) .ok_or(TokenError::Overflow)?; - - source_account_info.close(); + // Closes the source account. + source_account_info.close_unchecked(); } Ok(()) From 2607b012a639d2420678a9817424e19c7de5f108 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 25 Nov 2024 20:50:09 +0000 Subject: [PATCH 284/335] Switch to no_std --- p-token/Cargo.toml | 1 + p-token/src/lib.rs | 4 +- p-token/src/processor/amount_to_ui_amount.rs | 17 +++- p-token/src/processor/mod.rs | 88 ++++++++++++-------- p-token/src/processor/ui_amount_to_amount.rs | 7 +- 5 files changed, 73 insertions(+), 44 deletions(-) diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index a2608d7..68b039b 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -19,6 +19,7 @@ test-sbf = [] [dependencies] pinocchio = { workspace = true } +pinocchio-log = { workspace = true } pinocchio-pubkey = { workspace = true } token-interface = { version = "^0", path = "../interface" } diff --git a/p-token/src/lib.rs b/p-token/src/lib.rs index 8b786ad..f19f387 100644 --- a/p-token/src/lib.rs +++ b/p-token/src/lib.rs @@ -1,4 +1,6 @@ -//! An ERC20-like Token program for the Solana blockchain. +//! Another ERC20-like Token program for the Solana blockchain. + +#![no_std] mod entrypoint; mod processor; diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 3328fdb..98c9698 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -1,9 +1,11 @@ +use core::str::from_utf8_unchecked; use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; +use pinocchio_log::logger::{Argument, Logger}; use token_interface::state::mint::Mint; -use super::{amount_to_ui_amount_string_trimmed, check_account_owner}; +use super::{check_account_owner, MAX_DIGITS_U64}; #[inline(always)] pub fn process_amount_to_ui_amount( @@ -21,8 +23,17 @@ pub fn process_amount_to_ui_amount( let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; - let ui_amount = amount_to_ui_amount_string_trimmed(amount, mint.decimals); - set_return_data(&ui_amount.into_bytes()); + let mut logger = Logger::::default(); + logger.append_with_args(amount, &[Argument::Precision(mint.decimals)]); + + let mut s = unsafe { from_utf8_unchecked(&logger) }; + + if mint.decimals > 0 { + let zeros_trimmed = s.trim_end_matches('0'); + s = zeros_trimmed.trim_end_matches('.'); + } + + set_return_data(s.as_bytes()); Ok(()) } diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index a8dd6c4..3f69c04 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -1,5 +1,7 @@ +use core::{mem::MaybeUninit, slice::from_raw_parts, str::from_utf8_unchecked}; use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, syscalls::sol_memcpy_, + ProgramResult, }; use token_interface::{ error::TokenError, @@ -67,6 +69,12 @@ const INCINERATOR_ID: Pubkey = /// System program id. const SYSTEM_PROGRAM_ID: Pubkey = pinocchio_pubkey::pubkey!("11111111111111111111111111111111"); +/// An uninitialized byte. +const UNINIT_BYTE: MaybeUninit = MaybeUninit::uninit(); + +/// Maximum number of digits in a `u64``. +const MAX_DIGITS_U64: usize = 20; + #[inline(always)] fn is_owned_by_system_program_or_incinerator(owner: &Pubkey) -> bool { &SYSTEM_PROGRAM_ID == owner || &INCINERATOR_ID == owner @@ -120,44 +128,31 @@ fn validate_owner( Ok(()) } -/// Convert a raw amount to its UI representation using the given decimals field -/// Excess zeroes or unneeded decimal point are trimmed. -#[inline(always)] -fn amount_to_ui_amount_string_trimmed(amount: u64, decimals: u8) -> String { - let mut s = amount_to_ui_amount_string(amount, decimals); - if decimals > 0 { - let zeros_trimmed = s.trim_end_matches('0'); - s = zeros_trimmed.trim_end_matches('.').to_string(); - } - s -} - -/// Convert a raw amount to its UI representation (using the decimals field -/// defined in its mint) -#[inline(always)] -fn amount_to_ui_amount_string(amount: u64, decimals: u8) -> String { - let decimals = decimals as usize; - if decimals > 0 { - // Left-pad zeros to decimals + 1, so we at least have an integer zero - let mut s = format!("{:01$}", amount, decimals + 1); - // Add the decimal point (Sorry, "," locales!) - s.insert(s.len() - decimals, '.'); - s - } else { - amount.to_string() - } -} - /// Try to convert a UI representation of a token amount to its raw amount using /// the given decimals field -fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result { +fn try_ui_amount_into_amount(ui_amount: &str, decimals: u8) -> Result { let decimals = decimals as usize; let mut parts = ui_amount.split('.'); + // splitting a string, even an empty one, will always yield an iterator of at // least length == 1 - let mut amount_str = parts.next().unwrap().to_string(); + let amount_str = parts.next().unwrap(); + let mut length = amount_str.len(); + + let mut digits = [UNINIT_BYTE; MAX_DIGITS_U64]; + let mut ptr = digits.as_mut_ptr(); + + unsafe { + sol_memcpy_( + ptr as *mut _, + amount_str.as_ptr() as *const _, + length as u64, + ); + } + let after_decimal = parts.next().unwrap_or(""); let after_decimal = after_decimal.trim_end_matches('0'); + if (amount_str.is_empty() && after_decimal.is_empty()) || parts.next().is_some() || after_decimal.len() > decimals @@ -165,11 +160,30 @@ fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result() + .map_err(|_| ProgramError::InvalidArgument) } - amount_str - .parse::() - .map_err(|_| ProgramError::InvalidArgument) } diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index 5eb0bd7..31b4c17 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -1,3 +1,4 @@ +use core::str::from_utf8; use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; @@ -10,15 +11,15 @@ pub fn process_ui_amount_to_amount( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let ui_amount = core::str::from_utf8(instruction_data) - .map_err(|_error| ProgramError::InvalidInstructionData)?; + let ui_amount = + from_utf8(instruction_data).map_err(|_error| ProgramError::InvalidInstructionData)?; let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; - let amount = try_ui_amount_into_amount(ui_amount.to_string(), mint.decimals)?; + let amount = try_ui_amount_into_amount(ui_amount, mint.decimals)?; set_return_data(&amount.to_le_bytes()); Ok(()) From df8b6aa38adf138001279190b521878a34448318 Mon Sep 17 00:00:00 2001 From: febo Date: Wed, 27 Nov 2024 23:45:00 +0000 Subject: [PATCH 285/335] Fix amount conversion --- p-token/src/processor/amount_to_ui_amount.rs | 14 ++++- p-token/src/processor/mod.rs | 61 ++++++++++++-------- p-token/src/processor/ui_amount_to_amount.rs | 2 +- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 98c9698..1b2034a 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -7,6 +7,12 @@ use token_interface::state::mint::Mint; use super::{check_account_owner, MAX_DIGITS_U64}; +/// Maximum length of the UI amount string. +/// +/// The length includes the maximum number of digits in a `u64`` (20) +/// and the maximum number of punctuation characters (2). +const MAX_UI_AMOUNT_LENGTH: usize = MAX_DIGITS_U64 + 2; + #[inline(always)] pub fn process_amount_to_ui_amount( accounts: &[AccountInfo], @@ -20,12 +26,14 @@ pub fn process_amount_to_ui_amount( let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; - + // SAFETY: there is a single borrow to the `Mint` account. let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; - let mut logger = Logger::::default(); + let mut logger = Logger::::default(); logger.append_with_args(amount, &[Argument::Precision(mint.decimals)]); - + // "Extract" the formatted string from the logger. + // + // SAFETY: the logger is guaranteed to be a valid UTF-8 string. let mut s = unsafe { from_utf8_unchecked(&logger) }; if mint.decimals > 0 { diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 3f69c04..8a0ee5e 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -1,6 +1,11 @@ -use core::{mem::MaybeUninit, slice::from_raw_parts, str::from_utf8_unchecked}; +use core::{ + cmp::max, + mem::MaybeUninit, + slice::{from_raw_parts, from_raw_parts_mut}, + str::from_utf8_unchecked, +}; use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, syscalls::sol_memcpy_, + account_info::AccountInfo, memory::sol_memcpy, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; use token_interface::{ @@ -134,46 +139,53 @@ fn try_ui_amount_into_amount(ui_amount: &str, decimals: u8) -> Result decimals + || (length + expected_after_decimal_length) > MAX_DIGITS_U64 { return Err(ProgramError::InvalidArgument); } + let mut digits = [UNINIT_BYTE; MAX_DIGITS_U64]; + // SAFETY: `digits` is an array of `MaybeUninit`, which has the same + // memory layout as `u8`. + let slice: &mut [u8] = + unsafe { from_raw_parts_mut(digits.as_mut_ptr() as *mut _, MAX_DIGITS_U64) }; + + // SAFETY: the total length of `amount_str` and `after_decimal` is less than + // `MAX_DIGITS_U64`. unsafe { - sol_memcpy_( - ptr.add(length) as *mut _, - after_decimal.as_ptr() as *const _, - after_decimal.len() as u64, - ); + sol_memcpy(slice, amount_str.as_bytes(), length); - length += after_decimal.len(); - ptr = ptr.add(length); + sol_memcpy( + &mut slice[length..], + after_decimal.as_bytes(), + after_decimal.len(), + ); } + length += after_decimal.len(); let remaining = decimals.saturating_sub(after_decimal.len()); + // SAFETY: `digits` is an array of `MaybeUninit`, which has the same memory + // layout as `u8`. + let ptr = unsafe { digits.as_mut_ptr().add(length) }; + for offset in 0..remaining { + // SAFETY: `ptr` is within the bounds of `digits`. unsafe { (ptr.add(offset) as *mut u8).write(b'0'); } @@ -181,6 +193,7 @@ fn try_ui_amount_into_amount(ui_amount: &str, decimals: u8) -> Result() diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index 31b4c17..c16b837 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -16,7 +16,7 @@ pub fn process_ui_amount_to_amount( let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; - + // SAFETY: there is a single borrow to the `Mint` account. let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; let amount = try_ui_amount_into_amount(ui_amount, mint.decimals)?; From 3db0680aa5fcd636e0921cc9584b4c1df2c7e42e Mon Sep 17 00:00:00 2001 From: febo Date: Wed, 27 Nov 2024 23:45:50 +0000 Subject: [PATCH 286/335] Add amount ui tests --- p-token/Cargo.toml | 2 +- p-token/tests/amount_to_ui_amount.rs | 50 ++++++++++++++++++++++++++++ p-token/tests/setup/mint.rs | 2 +- p-token/tests/ui_amount_to_amount.rs | 50 ++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 p-token/tests/amount_to_ui_amount.rs create mode 100644 p-token/tests/ui_amount_to_amount.rs diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 68b039b..0351298 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -28,4 +28,4 @@ assert_matches = "1.5.0" solana-program-test = "~1.18" solana-sdk = "~1.18" spl-token = { version="^4", features=["no-entrypoint"] } -test-case = "3.3.1" \ No newline at end of file +test-case = "3.3.1" diff --git a/p-token/tests/amount_to_ui_amount.rs b/p-token/tests/amount_to_ui_amount.rs new file mode 100644 index 0000000..463061a --- /dev/null +++ b/p-token/tests/amount_to_ui_amount.rs @@ -0,0 +1,50 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::mint; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn amount_to_ui_amount(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority, + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + let mut amount_to_ui_amount_ix = + spl_token::instruction::amount_to_ui_amount(&spl_token::ID, &mint, 1000).unwrap(); + // Switches the program id to the token program. + amount_to_ui_amount_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[amount_to_ui_amount_ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the transaction should succeed. + + let account = context.banks_client.get_account(mint).await.unwrap(); + + assert!(account.is_some()); +} diff --git a/p-token/tests/setup/mint.rs b/p-token/tests/setup/mint.rs index 146aae4..2714757 100644 --- a/p-token/tests/setup/mint.rs +++ b/p-token/tests/setup/mint.rs @@ -24,7 +24,7 @@ pub async fn initialize( &account.pubkey(), &mint_authority, freeze_authority.as_ref(), - 0, + 4, ) .unwrap(); // Switches the program id in case we are using a "custom" one. diff --git a/p-token/tests/ui_amount_to_amount.rs b/p-token/tests/ui_amount_to_amount.rs new file mode 100644 index 0000000..e104c58 --- /dev/null +++ b/p-token/tests/ui_amount_to_amount.rs @@ -0,0 +1,50 @@ +#![cfg(feature = "test-sbf")] + +mod setup; + +use setup::mint; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; + +#[test_case::test_case(spl_token::ID ; "spl-token")] +#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[tokio::test] +async fn ui_amount_to_amount(token_program: Pubkey) { + let program_id = Pubkey::new_from_array(token_program::ID); + let mut context = ProgramTest::new("token_program", program_id, None) + .start_with_context() + .await; + + // Given a mint account. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority, + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + let mut ui_amount_to_amount_ix = + spl_token::instruction::ui_amount_to_amount(&spl_token::ID, &mint, "1000.00").unwrap(); + // Switches the program id to the token program. + ui_amount_to_amount_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[ui_amount_to_amount_ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the transaction should succeed. + + let account = context.banks_client.get_account(mint).await.unwrap(); + + assert!(account.is_some()); +} From 4ef1daa41848ee12213ca47b903c3a0717020ae6 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Thu, 28 Nov 2024 22:29:38 +0000 Subject: [PATCH 287/335] rafactor: Add trait types (#3) * Add trait types * Use load functions * Fix decimals value --- interface/src/state/account.rs | 119 ++++++------------ interface/src/state/mint.rs | 107 ++++------------ interface/src/state/mod.rs | 85 +++++++++++++ interface/src/state/multisig.rs | 81 ++---------- p-token/src/processor/amount_to_ui_amount.rs | 9 +- p-token/src/processor/close_account.rs | 24 +++- .../src/processor/get_account_data_size.rs | 9 +- .../processor/initialize_immutable_owner.rs | 8 +- p-token/src/processor/initialize_mint.rs | 7 +- p-token/src/processor/mod.rs | 20 +-- p-token/src/processor/revoke.rs | 7 +- p-token/src/processor/set_authority.rs | 6 +- p-token/src/processor/shared/approve.rs | 6 +- p-token/src/processor/shared/burn.rs | 12 +- .../processor/shared/initialize_account.rs | 38 +++--- .../processor/shared/initialize_multisig.rs | 16 ++- p-token/src/processor/shared/mint_to.rs | 30 ++--- .../processor/shared/toggle_account_state.rs | 6 +- p-token/src/processor/shared/transfer.rs | 48 ++++--- p-token/src/processor/sync_native.rs | 7 +- p-token/src/processor/ui_amount_to_amount.rs | 4 +- p-token/tests/approve_checked.rs | 2 +- p-token/tests/burn_checked.rs | 2 +- p-token/tests/mint_to_checked.rs | 2 +- p-token/tests/transfer_checked.rs | 2 +- 25 files changed, 299 insertions(+), 358 deletions(-) diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index fbe6377..65e8c69 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -1,12 +1,13 @@ -use pinocchio::{ - account_info::{AccountInfo, Ref}, - program_error::ProgramError, - pubkey::Pubkey, -}; +use pinocchio::pubkey::Pubkey; -use crate::program::ID; +use super::{account_state::AccountState, COption, Initializable, RawType}; -use super::{account_state::AccountState, COption}; +/// Incinerator address. +const INCINERATOR_ID: Pubkey = + pinocchio_pubkey::pubkey!("1nc1nerator11111111111111111111111111111111"); + +/// System program id. +const SYSTEM_PROGRAM_ID: Pubkey = pinocchio_pubkey::pubkey!("11111111111111111111111111111111"); /// Internal representation of a token account data. #[repr(C)] @@ -44,89 +45,28 @@ pub struct Account { } impl Account { - pub const LEN: usize = core::mem::size_of::(); - - /// Return a `TokenAccount` from the given account info. - /// - /// This method performs owner and length validation on `AccountInfo`, safe borrowing - /// the account data. - #[inline] - pub fn from_account_info(account_info: &AccountInfo) -> Result, ProgramError> { - if account_info.data_len() != Self::LEN { - return Err(ProgramError::InvalidAccountData); - } - if account_info.owner() != &ID { - return Err(ProgramError::InvalidAccountData); - } - Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe { - Self::from_bytes(data) - })) - } - - /// Return a `TokenAccount` from the given account info. - /// - /// This method performs owner and length validation on `AccountInfo`, but does not - /// perform the borrow check. - /// - /// # Safety - /// - /// The caller must ensure that it is safe to borrow the account data – e.g., there are - /// no mutable borrows of the account data. - #[inline] - pub unsafe fn from_account_info_unchecked( - account_info: &AccountInfo, - ) -> Result<&Account, ProgramError> { - if account_info.data_len() != Self::LEN { - return Err(ProgramError::InvalidAccountData); - } - if account_info.owner() != &ID { - return Err(ProgramError::InvalidAccountData); - } - Ok(Self::from_bytes(account_info.borrow_data_unchecked())) - } - - /// Return a `TokenAccount` from the given bytes. - /// - /// # Safety - /// - /// The caller must ensure that `bytes` contains a valid representation of `TokenAccount`. - #[inline(always)] - pub unsafe fn from_bytes(bytes: &[u8]) -> &Self { - &*(bytes.as_ptr() as *const Account) - } - - /// Return a mutable `Mint` reference from the given bytes. - /// - /// # Safety - /// - /// The caller must ensure that `bytes` contains a valid representation of `Mint`. #[inline(always)] - pub unsafe fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self { - &mut *(bytes.as_mut_ptr() as *mut Account) - } - - #[inline] pub fn set_amount(&mut self, amount: u64) { self.amount = amount.to_le_bytes(); } - #[inline] + #[inline(always)] pub fn amount(&self) -> u64 { u64::from_le_bytes(self.amount) } - #[inline] + #[inline(always)] pub fn clear_delegate(&mut self) { self.delegate.0[0] = 0; } - #[inline] + #[inline(always)] pub fn set_delegate(&mut self, delegate: &Pubkey) { self.delegate.0[0] = 1; self.delegate.1 = *delegate; } - #[inline] + #[inline(always)] pub fn delegate(&self) -> Option<&Pubkey> { if self.delegate.0[0] == 1 { Some(&self.delegate.1) @@ -135,17 +75,17 @@ impl Account { } } - #[inline] + #[inline(always)] pub fn set_native(&mut self, value: bool) { self.is_native[0] = value as u8; } - #[inline] + #[inline(always)] pub fn is_native(&self) -> bool { self.is_native[0] == 1 } - #[inline] + #[inline(always)] pub fn native_amount(&self) -> Option { if self.is_native() { Some(u64::from_le_bytes(self.native_amount)) @@ -154,28 +94,28 @@ impl Account { } } - #[inline] + #[inline(always)] pub fn set_delegated_amount(&mut self, amount: u64) { self.delegated_amount = amount.to_le_bytes(); } - #[inline] + #[inline(always)] pub fn delegated_amount(&self) -> u64 { u64::from_le_bytes(self.delegated_amount) } - #[inline] + #[inline(always)] pub fn clear_close_authority(&mut self) { self.close_authority.0[0] = 0; } - #[inline] + #[inline(always)] pub fn set_close_authority(&mut self, value: &Pubkey) { self.close_authority.0[0] = 1; self.close_authority.1 = *value; } - #[inline] + #[inline(always)] pub fn close_authority(&self) -> Option<&Pubkey> { if self.close_authority.0[0] == 1 { Some(&self.close_authority.1) @@ -185,12 +125,23 @@ impl Account { } #[inline(always)] - pub fn is_initialized(&self) -> bool { - self.state != AccountState::Uninitialized + pub fn is_frozen(&self) -> bool { + self.state == AccountState::Frozen } #[inline(always)] - pub fn is_frozen(&self) -> bool { - self.state == AccountState::Frozen + pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { + SYSTEM_PROGRAM_ID == self.owner || INCINERATOR_ID == self.owner + } +} + +impl RawType for Account { + const LEN: usize = core::mem::size_of::(); +} + +impl Initializable for Account { + #[inline(always)] + fn is_initialized(&self) -> bool { + self.state != AccountState::Uninitialized } } diff --git a/interface/src/state/mint.rs b/interface/src/state/mint.rs index 1ca3d90..3b4d41b 100644 --- a/interface/src/state/mint.rs +++ b/interface/src/state/mint.rs @@ -1,12 +1,6 @@ -use pinocchio::{ - account_info::{AccountInfo, Ref}, - program_error::ProgramError, - pubkey::Pubkey, -}; +use pinocchio::pubkey::Pubkey; -use crate::program::ID; - -use super::COption; +use super::{COption, Initializable, RawType}; /// Internal representation of a mint data. #[repr(C)] @@ -33,100 +27,33 @@ pub struct Mint { } impl Mint { - /// The length of the `Mint` account data. - pub const LEN: usize = core::mem::size_of::(); - - /// Return a `Mint` from the given account info. - /// - /// This method performs owner and length validation on `AccountInfo`, safe borrowing - /// the account data. - #[inline] - pub fn from_account_info(account_info: &AccountInfo) -> Result, ProgramError> { - if account_info.data_len() != Self::LEN { - return Err(ProgramError::InvalidAccountData); - } - if account_info.owner() != &ID { - return Err(ProgramError::InvalidAccountOwner); - } - Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe { - Self::from_bytes(data) - })) - } - - /// Return a `Mint` from the given account info. - /// - /// This method performs owner and length validation on `AccountInfo`, but does not - /// perform the borrow check. - /// - /// # Safety - /// - /// The caller must ensure that it is safe to borrow the account data – e.g., there are - /// no mutable borrows of the account data. - #[inline] - pub unsafe fn from_account_info_unchecked( - account_info: &AccountInfo, - ) -> Result<&Self, ProgramError> { - if account_info.data_len() != Self::LEN { - return Err(ProgramError::InvalidAccountData); - } - if account_info.owner() != &ID { - return Err(ProgramError::InvalidAccountOwner); - } - Ok(Self::from_bytes(account_info.borrow_data_unchecked())) - } - - /// Return a `Mint` reference from the given bytes. - /// - /// # Safety - /// - /// The caller must ensure that `bytes` contains a valid representation of `Mint`. - #[inline] - pub unsafe fn from_bytes(bytes: &[u8]) -> &Self { - &*(bytes.as_ptr() as *const Mint) - } - - /// Return a mutable `Mint` reference from the given bytes. - /// - /// # Safety - /// - /// The caller must ensure that `bytes` contains a valid representation of `Mint`. - #[inline] - pub unsafe fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self { - &mut *(bytes.as_mut_ptr() as *mut Mint) - } - - #[inline] + #[inline(always)] pub fn set_supply(&mut self, supply: u64) { self.supply = supply.to_le_bytes(); } - #[inline] + #[inline(always)] pub fn supply(&self) -> u64 { u64::from_le_bytes(self.supply) } - #[inline] + #[inline(always)] pub fn set_initialized(&mut self, value: bool) { self.is_initialized = value as u8; } - #[inline] - pub fn is_initialized(&self) -> bool { - self.is_initialized == 1 - } - - #[inline] + #[inline(always)] pub fn clear_mint_authority(&mut self) { self.mint_authority.0[0] = 0; } - #[inline] + #[inline(always)] pub fn set_mint_authority(&mut self, mint_authority: &Pubkey) { self.mint_authority.0[0] = 1; self.mint_authority.1 = *mint_authority; } - #[inline] + #[inline(always)] pub fn mint_authority(&self) -> Option<&Pubkey> { if self.mint_authority.0[0] == 1 { Some(&self.mint_authority.1) @@ -135,18 +62,18 @@ impl Mint { } } - #[inline] + #[inline(always)] pub fn clear_freeze_authority(&mut self) { self.freeze_authority.0[0] = 0; } - #[inline] + #[inline(always)] pub fn set_freeze_authority(&mut self, freeze_authority: &Pubkey) { self.freeze_authority.0[0] = 1; self.freeze_authority.1 = *freeze_authority; } - #[inline] + #[inline(always)] pub fn freeze_authority(&self) -> Option<&Pubkey> { if self.freeze_authority.0[0] == 1 { Some(&self.freeze_authority.1) @@ -155,3 +82,15 @@ impl Mint { } } } + +impl RawType for Mint { + /// The length of the `Mint` account data. + const LEN: usize = core::mem::size_of::(); +} + +impl Initializable for Mint { + #[inline(always)] + fn is_initialized(&self) -> bool { + self.is_initialized == 1 + } +} diff --git a/interface/src/state/mod.rs b/interface/src/state/mod.rs index 04c0342..b7c35df 100644 --- a/interface/src/state/mod.rs +++ b/interface/src/state/mod.rs @@ -1,3 +1,5 @@ +use pinocchio::program_error::ProgramError; + pub mod account; pub mod account_state; pub mod mint; @@ -5,3 +7,86 @@ pub mod multisig; /// Type alias for fields represented as `COption`. pub type COption = ([u8; 4], T); + +/// Marker trait for types that can cast from a raw pointer. +/// +/// It is up to the type implementing this trait to guarantee that the cast is safe, +/// i.e., that the fields of the type are well aligned and there are no padding bytes. +pub trait RawType { + /// The length of the type. + /// + /// This must be equal to the size of each individual field in the type. + const LEN: usize; +} + +/// Trait to represent a type that can be initialized. +pub trait Initializable { + /// Return `true` if the object is initialized. + fn is_initialized(&self) -> bool; +} + +/// Return a reference for an initialized `T` from the given bytes. +/// +/// # Safety +/// +/// The caller must ensure that `bytes` contains a valid representation of `T`. +#[inline(always)] +pub unsafe fn load(bytes: &[u8]) -> Result<&T, ProgramError> { + load_unchecked(bytes).and_then(|t: &T| { + // checks if the data is initialized + if t.is_initialized() { + Ok(t) + } else { + Err(ProgramError::UninitializedAccount) + } + }) +} + +/// Return a `T` reference from the given bytes. +/// +/// This function does not check if the data is initialized. +/// +/// # Safety +/// +/// The caller must ensure that `bytes` contains a valid representation of `T`. +#[inline(always)] +pub unsafe fn load_unchecked(bytes: &[u8]) -> Result<&T, ProgramError> { + if bytes.len() != T::LEN { + return Err(ProgramError::InvalidAccountData); + } + Ok(&*(bytes.as_ptr() as *const T)) +} + +/// Return a mutable reference for an initialized `T` from the given bytes. +/// +/// # Safety +/// +/// The caller must ensure that `bytes` contains a valid representation of `T`. +#[inline(always)] +pub unsafe fn load_mut( + bytes: &mut [u8], +) -> Result<&mut T, ProgramError> { + load_mut_unchecked(bytes).and_then(|t: &mut T| { + // checks if the data is initialized + if t.is_initialized() { + Ok(t) + } else { + Err(ProgramError::UninitializedAccount) + } + }) +} + +/// Return a mutable `T` reference from the given bytes. +/// +/// This function does not check if the data is initialized. +/// +/// # Safety +/// +/// The caller must ensure that `bytes` contains a valid representation of `T`. +#[inline(always)] +pub unsafe fn load_mut_unchecked(bytes: &mut [u8]) -> Result<&mut T, ProgramError> { + if bytes.len() != T::LEN { + return Err(ProgramError::InvalidAccountData); + } + Ok(&mut *(bytes.as_mut_ptr() as *mut T)) +} diff --git a/interface/src/state/multisig.rs b/interface/src/state/multisig.rs index 362c614..920da97 100644 --- a/interface/src/state/multisig.rs +++ b/interface/src/state/multisig.rs @@ -1,10 +1,6 @@ -use pinocchio::{ - account_info::{AccountInfo, Ref}, - program_error::ProgramError, - pubkey::Pubkey, -}; +use pinocchio::pubkey::Pubkey; -use crate::program::ID; +use super::{Initializable, RawType}; /// Minimum number of multisignature signers (min N) pub const MIN_SIGNERS: usize = 1; @@ -29,68 +25,6 @@ pub struct Multisig { } impl Multisig { - /// The length of the `Multisig` account data. - pub const LEN: usize = core::mem::size_of::(); - - /// Return a `Multisig` from the given account info. - /// - /// This method performs owner and length validation on `AccountInfo`, safe borrowing - /// the account data. - #[inline] - pub fn from_account_info(account_info: &AccountInfo) -> Result, ProgramError> { - if account_info.data_len() != Self::LEN { - return Err(ProgramError::InvalidAccountData); - } - if account_info.owner() != &ID { - return Err(ProgramError::InvalidAccountOwner); - } - Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe { - Self::from_bytes(data) - })) - } - - /// Return a `Multisig` from the given account info. - /// - /// This method performs owner and length validation on `AccountInfo`, but does not - /// perform the borrow check. - /// - /// # Safety - /// - /// The caller must ensure that it is safe to borrow the account data – e.g., there are - /// no mutable borrows of the account data. - #[inline] - pub unsafe fn from_account_info_unchecked( - account_info: &AccountInfo, - ) -> Result<&Self, ProgramError> { - if account_info.data_len() != Self::LEN { - return Err(ProgramError::InvalidAccountData); - } - if account_info.owner() != &ID { - return Err(ProgramError::InvalidAccountOwner); - } - Ok(Self::from_bytes(account_info.borrow_data_unchecked())) - } - - /// Return a `Multisig` reference from the given bytes. - /// - /// # Safety - /// - /// The caller must ensure that `bytes` contains a valid representation of `Multisig`. - #[inline] - pub unsafe fn from_bytes(bytes: &[u8]) -> &Self { - &*(bytes.as_ptr() as *const Multisig) - } - - /// Return a mutable `Multisig` reference from the given bytes. - /// - /// # Safety - /// - /// The caller must ensure that `bytes` contains a valid representation of `Multisig`. - #[inline] - pub unsafe fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self { - &mut *(bytes.as_mut_ptr() as *mut Multisig) - } - /// Utility function that checks index is between [`MIN_SIGNERS`] and [`MAX_SIGNERS`]. pub fn is_valid_signer_index(index: usize) -> bool { (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) @@ -100,9 +34,16 @@ impl Multisig { pub fn set_initialized(&mut self, value: bool) { self.is_initialized = value as u8; } +} - #[inline] - pub fn is_initialized(&self) -> bool { +impl RawType for Multisig { + /// The length of the `Mint` account data. + const LEN: usize = core::mem::size_of::(); +} + +impl Initializable for Multisig { + #[inline(always)] + fn is_initialized(&self) -> bool { self.is_initialized == 1 } } diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 1b2034a..828e713 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -3,7 +3,10 @@ use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; use pinocchio_log::logger::{Argument, Logger}; -use token_interface::state::mint::Mint; +use token_interface::{ + error::TokenError, + state::{load, mint::Mint}, +}; use super::{check_account_owner, MAX_DIGITS_U64}; @@ -27,7 +30,9 @@ pub fn process_amount_to_ui_amount( let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; // SAFETY: there is a single borrow to the `Mint` account. - let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; + let mint = unsafe { + load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? + }; let mut logger = Logger::::default(); logger.append_with_args(amount, &[Argument::Precision(mint.decimals)]); diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs index 8f5e79c..ffd0263 100644 --- a/p-token/src/processor/close_account.rs +++ b/p-token/src/processor/close_account.rs @@ -1,7 +1,16 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{error::TokenError, state::account::Account}; +use pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +}; +use token_interface::{ + error::TokenError, + state::{account::Account, load_mut}, +}; -use super::{is_owned_by_system_program_or_incinerator, validate_owner, INCINERATOR_ID}; +use super::validate_owner; + +/// Incinerator address. +const INCINERATOR_ID: Pubkey = + pinocchio_pubkey::pubkey!("1nc1nerator11111111111111111111111111111111"); #[inline(always)] pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { @@ -10,12 +19,15 @@ pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { return Err(ProgramError::NotEnoughAccountKeys); }; - if source_account_info.key() == destination_account_info.key() { + // Comparing whether the AccountInfo's "point" to the same account or + // not - this is a faster comparison since it just checks the internal + // raw pointer. + if source_account_info == destination_account_info { return Err(ProgramError::InvalidAccountData); } let source_account = - unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; if !source_account.is_native() && source_account.amount() != 0 { return Err(TokenError::NonNativeHasBalance.into()); @@ -25,7 +37,7 @@ pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { .close_authority() .unwrap_or(&source_account.owner); - if !is_owned_by_system_program_or_incinerator(source_account_info.owner()) { + if !source_account.is_owned_by_system_program_or_incinerator() { validate_owner(authority, authority_info, remaining)?; } else if destination_account_info.key() != &INCINERATOR_ID { return Err(ProgramError::InvalidAccountData); diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index 5e96960..eb46a88 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -1,7 +1,10 @@ use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; -use token_interface::state::{account::Account, mint::Mint}; +use token_interface::{ + error::TokenError, + state::{account::Account, load, mint::Mint, RawType}, +}; use super::check_account_owner; @@ -14,7 +17,9 @@ pub fn process_get_account_data_size(accounts: &[AccountInfo]) -> ProgramResult // Make sure the mint is valid. check_account_owner(mint_info)?; - let _ = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; + let _ = unsafe { + load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint) + }; set_return_data(&Account::LEN.to_le_bytes()); diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs index 766e5b5..cf69da4 100644 --- a/p-token/src/processor/initialize_immutable_owner.rs +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -1,12 +1,14 @@ use pinocchio::{account_info::AccountInfo, msg, program_error::ProgramError, ProgramResult}; -use token_interface::{error::TokenError, state::account::Account}; +use token_interface::{ + error::TokenError, + state::{account::Account, load_unchecked, Initializable}, +}; #[inline(always)] pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { let token_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; - let account = - unsafe { Account::from_bytes_mut(token_account_info.borrow_mut_data_unchecked()) }; + let account = unsafe { load_unchecked::(token_account_info.borrow_data_unchecked())? }; if account.is_initialized() { return Err(TokenError::AlreadyInUse.into()); diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 752537d..8460ce0 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -6,7 +6,10 @@ use pinocchio::{ sysvars::{rent::Rent, Sysvar}, ProgramResult, }; -use token_interface::{error::TokenError, state::mint::Mint}; +use token_interface::{ + error::TokenError, + state::{load_mut_unchecked, mint::Mint, Initializable}, +}; #[inline(always)] pub fn process_initialize_mint( @@ -32,7 +35,7 @@ pub fn process_initialize_mint( (mint_info, None) }; - let mint = unsafe { Mint::from_bytes_mut(mint_info.borrow_mut_data_unchecked()) }; + let mint = unsafe { load_mut_unchecked::(mint_info.borrow_mut_data_unchecked())? }; if mint.is_initialized() { return Err(TokenError::AlreadyInUse.into()); diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 8a0ee5e..46adb30 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -10,7 +10,11 @@ use pinocchio::{ }; use token_interface::{ error::TokenError, - state::multisig::{Multisig, MAX_SIGNERS}, + state::{ + load, + multisig::{Multisig, MAX_SIGNERS}, + RawType, + }, }; pub mod amount_to_ui_amount; @@ -67,24 +71,12 @@ pub use transfer::process_transfer; pub use transfer_checked::process_transfer_checked; pub use ui_amount_to_amount::process_ui_amount_to_amount; -/// Incinerator address. -const INCINERATOR_ID: Pubkey = - pinocchio_pubkey::pubkey!("1nc1nerator11111111111111111111111111111111"); - -/// System program id. -const SYSTEM_PROGRAM_ID: Pubkey = pinocchio_pubkey::pubkey!("11111111111111111111111111111111"); - /// An uninitialized byte. const UNINIT_BYTE: MaybeUninit = MaybeUninit::uninit(); /// Maximum number of digits in a `u64``. const MAX_DIGITS_U64: usize = 20; -#[inline(always)] -fn is_owned_by_system_program_or_incinerator(owner: &Pubkey) -> bool { - &SYSTEM_PROGRAM_ID == owner || &INCINERATOR_ID == owner -} - /// Checks that the account is owned by the expected program. #[inline(always)] fn check_account_owner(account_info: &AccountInfo) -> ProgramResult { @@ -107,7 +99,7 @@ fn validate_owner( } if owner_account_info.data_len() == Multisig::LEN && &crate::ID != owner_account_info.owner() { - let multisig = unsafe { Multisig::from_bytes(owner_account_info.borrow_data_unchecked()) }; + let multisig = unsafe { load::(owner_account_info.borrow_data_unchecked())? }; let mut num_signers = 0; let mut matched = [false; MAX_SIGNERS]; diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs index 4ed5016..2d40b02 100644 --- a/p-token/src/processor/revoke.rs +++ b/p-token/src/processor/revoke.rs @@ -1,5 +1,8 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{error::TokenError, state::account::Account}; +use token_interface::{ + error::TokenError, + state::{account::Account, load_mut}, +}; use super::validate_owner; @@ -10,7 +13,7 @@ pub fn process_revoke(accounts: &[AccountInfo], _instruction_data: &[u8]) -> Pro }; let source_account = - unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index 4661342..2b9fd94 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -6,7 +6,7 @@ use pinocchio::{ use token_interface::{ error::TokenError, instruction::AuthorityType, - state::{account::Account, mint::Mint}, + state::{account::Account, load_mut, mint::Mint, RawType}, }; use super::validate_owner; @@ -27,7 +27,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) }; if account_info.data_len() == Account::LEN { - let account = unsafe { Account::from_bytes_mut(account_info.borrow_mut_data_unchecked()) }; + let account = unsafe { load_mut::(account_info.borrow_mut_data_unchecked())? }; if account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -65,7 +65,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) } } } else if account_info.data_len() == Mint::LEN { - let mint = unsafe { Mint::from_bytes_mut(account_info.borrow_mut_data_unchecked()) }; + let mint = unsafe { load_mut::(account_info.borrow_mut_data_unchecked())? }; match authority_type { AuthorityType::MintTokens => { diff --git a/p-token/src/processor/shared/approve.rs b/p-token/src/processor/shared/approve.rs index 5715a12..40fa7af 100644 --- a/p-token/src/processor/shared/approve.rs +++ b/p-token/src/processor/shared/approve.rs @@ -1,7 +1,7 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - state::{account::Account, mint::Mint}, + state::{account::Account, load, load_mut, mint::Mint}, }; use crate::processor::validate_owner; @@ -46,7 +46,7 @@ pub fn process_approve( // Validates source account. let source_account = - unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -57,7 +57,7 @@ pub fn process_approve( return Err(TokenError::MintMismatch.into()); } - let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; + let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; if expected_decimals != mint.decimals { return Err(TokenError::MintDecimalsMismatch.into()); diff --git a/p-token/src/processor/shared/burn.rs b/p-token/src/processor/shared/burn.rs index d23872f..1c26785 100644 --- a/p-token/src/processor/shared/burn.rs +++ b/p-token/src/processor/shared/burn.rs @@ -1,12 +1,10 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - state::{account::Account, mint::Mint}, + state::{account::Account, load_mut, mint::Mint}, }; -use crate::processor::{ - check_account_owner, is_owned_by_system_program_or_incinerator, validate_owner, -}; +use crate::processor::{check_account_owner, validate_owner}; #[inline(always)] pub fn process_burn( @@ -19,7 +17,7 @@ pub fn process_burn( }; let source_account = - unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -35,7 +33,7 @@ pub fn process_burn( .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; - let mint = unsafe { Mint::from_bytes_mut(mint_info.borrow_mut_data_unchecked()) }; + let mint = unsafe { load_mut::(mint_info.borrow_mut_data_unchecked())? }; if mint_info.key() != &source_account.mint { return Err(TokenError::MintMismatch.into()); @@ -47,7 +45,7 @@ pub fn process_burn( } } - if !is_owned_by_system_program_or_incinerator(&source_account.owner) { + if !source_account.is_owned_by_system_program_or_incinerator() { match source_account.delegate() { Some(delegate) if authority_info.key() == delegate => { validate_owner(delegate, authority_info, remaining)?; diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index fc66467..d751a72 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -1,4 +1,3 @@ -use core::mem::size_of; use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, @@ -9,7 +8,10 @@ use pinocchio::{ use token_interface::{ error::TokenError, native_mint::is_native_mint, - state::{account::Account, account_state::AccountState, mint::Mint}, + state::{ + account::Account, account_state::AccountState, load, load_mut_unchecked, mint::Mint, + Initializable, + }, }; use crate::processor::check_account_owner; @@ -36,36 +38,37 @@ pub fn process_initialize_account( // Check rent-exempt status of the token account. - let is_exempt = if rent_sysvar_account { + let new_account_info_data_len = new_account_info.data_len(); + + let minimum_balance = if rent_sysvar_account { let rent_sysvar_info = remaning.first().ok_or(ProgramError::NotEnoughAccountKeys)?; let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; - rent.is_exempt(new_account_info.lamports(), size_of::()) + rent.minimum_balance(new_account_info_data_len) } else { - Rent::get()?.is_exempt(new_account_info.lamports(), size_of::()) + Rent::get()?.minimum_balance(new_account_info_data_len) }; - if !is_exempt { - return Err(TokenError::NotRentExempt.into()); - } + let is_native_mint = is_native_mint(mint_info.key()); // Initialize the account. - let account = unsafe { Account::from_bytes_mut(new_account_info.borrow_mut_data_unchecked()) }; + let account = + unsafe { load_mut_unchecked::(new_account_info.borrow_mut_data_unchecked())? }; if account.is_initialized() { return Err(TokenError::AlreadyInUse.into()); } - let is_native_mint = is_native_mint(mint_info.key()); + if new_account_info.lamports() < minimum_balance { + return Err(TokenError::NotRentExempt.into()); + } if !is_native_mint { check_account_owner(mint_info)?; - let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; - - if !mint.is_initialized() { - return Err(TokenError::InvalidMint.into()); - } + let _ = unsafe { + load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? + }; } account.state = AccountState::Initialized; @@ -73,15 +76,12 @@ pub fn process_initialize_account( account.owner = *owner; if is_native_mint { - let rent = Rent::get()?; - let rent_exempt_reserve = rent.minimum_balance(size_of::()); - account.set_native(true); unsafe { account.set_amount( new_account_info .borrow_lamports_unchecked() - .checked_sub(rent_exempt_reserve) + .checked_sub(minimum_balance) .ok_or(TokenError::Overflow)?, ); } diff --git a/p-token/src/processor/shared/initialize_multisig.rs b/p-token/src/processor/shared/initialize_multisig.rs index cae5084..8831c19 100644 --- a/p-token/src/processor/shared/initialize_multisig.rs +++ b/p-token/src/processor/shared/initialize_multisig.rs @@ -4,7 +4,10 @@ use pinocchio::{ sysvars::{rent::Rent, Sysvar}, ProgramResult, }; -use token_interface::{error::TokenError, state::multisig::Multisig}; +use token_interface::{ + error::TokenError, + state::{load_mut_unchecked, multisig::Multisig, Initializable}, +}; #[inline(always)] pub fn process_initialize_multisig( @@ -35,16 +38,17 @@ pub fn process_initialize_multisig( Rent::get()?.is_exempt(multisig_info.lamports(), multisig_info_data_len) }; - if !is_exempt { - return Err(TokenError::NotRentExempt.into()); - } - - let multisig = unsafe { Multisig::from_bytes_mut(multisig_info.borrow_mut_data_unchecked()) }; + let multisig = + unsafe { load_mut_unchecked::(multisig_info.borrow_mut_data_unchecked())? }; if multisig.is_initialized() { return Err(TokenError::AlreadyInUse.into()); } + if !is_exempt { + return Err(TokenError::NotRentExempt.into()); + } + // Initialize the multisig account. multisig.m = m; diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs index cc891bd..7edd89e 100644 --- a/p-token/src/processor/shared/mint_to.rs +++ b/p-token/src/processor/shared/mint_to.rs @@ -1,7 +1,7 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - state::{account::Account, mint::Mint}, + state::{account::Account, load_mut, mint::Mint}, }; use crate::processor::{check_account_owner, validate_owner}; @@ -19,7 +19,7 @@ pub fn process_mint_to( // Validates the destination account. let destination_account = - unsafe { Account::from_bytes_mut(destination_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(destination_account_info.borrow_mut_data_unchecked())? }; if destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -33,7 +33,7 @@ pub fn process_mint_to( return Err(TokenError::MintMismatch.into()); } - let mint = unsafe { Mint::from_bytes_mut(mint_info.borrow_mut_data_unchecked()) }; + let mint = unsafe { load_mut::(mint_info.borrow_mut_data_unchecked())? }; if let Some(expected_decimals) = expected_decimals { if expected_decimals != mint.decimals { @@ -49,19 +49,19 @@ pub fn process_mint_to( if amount == 0 { check_account_owner(mint_info)?; check_account_owner(destination_account_info)?; - } - - let destination_amount = destination_account - .amount() - .checked_add(amount) - .ok_or(ProgramError::InvalidAccountData)?; - destination_account.set_amount(destination_amount); + } else { + let destination_amount = destination_account + .amount() + .checked_add(amount) + .ok_or(ProgramError::InvalidAccountData)?; + destination_account.set_amount(destination_amount); - let mint_supply = mint - .supply() - .checked_add(amount) - .ok_or(ProgramError::InvalidAccountData)?; - mint.set_supply(mint_supply); + let mint_supply = mint + .supply() + .checked_add(amount) + .ok_or(ProgramError::InvalidAccountData)?; + mint.set_supply(mint_supply); + } Ok(()) } diff --git a/p-token/src/processor/shared/toggle_account_state.rs b/p-token/src/processor/shared/toggle_account_state.rs index f52b619..bf05bfd 100644 --- a/p-token/src/processor/shared/toggle_account_state.rs +++ b/p-token/src/processor/shared/toggle_account_state.rs @@ -1,7 +1,7 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - state::{account::Account, account_state::AccountState, mint::Mint}, + state::{account::Account, account_state::AccountState, load, load_mut, mint::Mint}, }; use crate::processor::validate_owner; @@ -13,7 +13,7 @@ pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> P }; let source_account = - unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { return Err(TokenError::InvalidState.into()); @@ -25,7 +25,7 @@ pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> P return Err(TokenError::MintMismatch.into()); } - let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; + let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; match mint.freeze_authority() { Some(authority) => validate_owner(authority, authority_info, remaining), diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index d3818b3..6d33d5f 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -1,7 +1,7 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - state::{account::Account, mint::Mint}, + state::{account::Account, load, load_mut, mint::Mint}, }; use crate::processor::{check_account_owner, validate_owner}; @@ -52,10 +52,10 @@ pub fn process_transfer( // Validates source and destination accounts. let source_account = - unsafe { Account::from_bytes_mut(source_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; let destination_account = - unsafe { Account::from_bytes_mut(destination_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(destination_account_info.borrow_mut_data_unchecked())? }; if source_account.is_frozen() || destination_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -80,7 +80,7 @@ pub fn process_transfer( return Err(TokenError::MintMismatch.into()); } - let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; + let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; if decimals != mint.decimals { return Err(TokenError::MintDecimalsMismatch.into()); @@ -118,31 +118,29 @@ pub fn process_transfer( // to these account. check_account_owner(source_account_info)?; check_account_owner(destination_account_info)?; + } else { + // Moves the tokens. - return Ok(()); - } - - // Moves the tokens. - - source_account.set_amount(remaining_amount); - - let destination_amount = destination_account - .amount() - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - destination_account.set_amount(destination_amount); - - if source_account.is_native() { - let source_lamports = unsafe { source_account_info.borrow_mut_lamports_unchecked() }; - *source_lamports = source_lamports - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; + source_account.set_amount(remaining_amount); - let destination_lamports = - unsafe { destination_account_info.borrow_mut_lamports_unchecked() }; - *destination_lamports = destination_lamports + let destination_amount = destination_account + .amount() .checked_add(amount) .ok_or(TokenError::Overflow)?; + destination_account.set_amount(destination_amount); + + if source_account.is_native() { + let source_lamports = unsafe { source_account_info.borrow_mut_lamports_unchecked() }; + *source_lamports = source_lamports + .checked_sub(amount) + .ok_or(TokenError::Overflow)?; + + let destination_lamports = + unsafe { destination_account_info.borrow_mut_lamports_unchecked() }; + *destination_lamports = destination_lamports + .checked_add(amount) + .ok_or(TokenError::Overflow)?; + } } Ok(()) diff --git a/p-token/src/processor/sync_native.rs b/p-token/src/processor/sync_native.rs index fd90f2b..9bba708 100644 --- a/p-token/src/processor/sync_native.rs +++ b/p-token/src/processor/sync_native.rs @@ -1,5 +1,8 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{error::TokenError, state::account::Account}; +use token_interface::{ + error::TokenError, + state::{account::Account, load_mut}, +}; use super::check_account_owner; @@ -10,7 +13,7 @@ pub fn process_sync_native(accounts: &[AccountInfo]) -> ProgramResult { check_account_owner(native_account_info)?; let native_account = - unsafe { Account::from_bytes_mut(native_account_info.borrow_mut_data_unchecked()) }; + unsafe { load_mut::(native_account_info.borrow_mut_data_unchecked())? }; if let Option::Some(rent_exempt_reserve) = native_account.native_amount() { let new_amount = native_account_info diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index c16b837..752386e 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -2,7 +2,7 @@ use core::str::from_utf8; use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; -use token_interface::state::mint::Mint; +use token_interface::state::{load, mint::Mint}; use super::{check_account_owner, try_ui_amount_into_amount}; @@ -17,7 +17,7 @@ pub fn process_ui_amount_to_amount( let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; // SAFETY: there is a single borrow to the `Mint` account. - let mint = unsafe { Mint::from_bytes(mint_info.borrow_data_unchecked()) }; + let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; let amount = try_ui_amount_into_amount(ui_amount, mint.decimals)?; set_return_data(&amount.to_le_bytes()); diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs index 63b3ad7..8320572 100644 --- a/p-token/tests/approve_checked.rs +++ b/p-token/tests/approve_checked.rs @@ -63,7 +63,7 @@ async fn approve_checked(token_program: Pubkey) { &owner.pubkey(), &[], 50, - 0, + 4, ) .unwrap(); approve_ix.program_id = token_program; diff --git a/p-token/tests/burn_checked.rs b/p-token/tests/burn_checked.rs index 0502653..d53e21b 100644 --- a/p-token/tests/burn_checked.rs +++ b/p-token/tests/burn_checked.rs @@ -60,7 +60,7 @@ async fn burn_checked(token_program: Pubkey) { &owner.pubkey(), &[], 50, - 0, + 4, ) .unwrap(); burn_ix.program_id = token_program; diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs index 42fcb8f..c6ecf54 100644 --- a/p-token/tests/mint_to_checked.rs +++ b/p-token/tests/mint_to_checked.rs @@ -49,7 +49,7 @@ async fn mint_to_checked(token_program: Pubkey) { &mint_authority.pubkey(), &[], 100, - 0, + 4, ) .unwrap(); // Switches the program id to the token program. diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs index 9616d22..b4c2865 100644 --- a/p-token/tests/transfer_checked.rs +++ b/p-token/tests/transfer_checked.rs @@ -66,7 +66,7 @@ async fn transfer_checked(token_program: Pubkey) { &owner.pubkey(), &[], 100, - 0, + 4, ) .unwrap(); transfer_ix.program_id = token_program; From 982a51cf845bdd370e5d8f188abddc5b987e65c3 Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 28 Nov 2024 23:12:34 +0000 Subject: [PATCH 288/335] Increase formatting buffer --- p-token/src/processor/amount_to_ui_amount.rs | 10 ++-------- p-token/src/processor/mod.rs | 14 +++++++++----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 828e713..40fc13c 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -8,13 +8,7 @@ use token_interface::{ state::{load, mint::Mint}, }; -use super::{check_account_owner, MAX_DIGITS_U64}; - -/// Maximum length of the UI amount string. -/// -/// The length includes the maximum number of digits in a `u64`` (20) -/// and the maximum number of punctuation characters (2). -const MAX_UI_AMOUNT_LENGTH: usize = MAX_DIGITS_U64 + 2; +use super::{check_account_owner, MAX_FORMATTED_DIGITS}; #[inline(always)] pub fn process_amount_to_ui_amount( @@ -34,7 +28,7 @@ pub fn process_amount_to_ui_amount( load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? }; - let mut logger = Logger::::default(); + let mut logger = Logger::::default(); logger.append_with_args(amount, &[Argument::Precision(mint.decimals)]); // "Extract" the formatted string from the logger. // diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 46adb30..ae96986 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -74,8 +74,12 @@ pub use ui_amount_to_amount::process_ui_amount_to_amount; /// An uninitialized byte. const UNINIT_BYTE: MaybeUninit = MaybeUninit::uninit(); -/// Maximum number of digits in a `u64``. -const MAX_DIGITS_U64: usize = 20; +/// Maximum number of digits in a formatted `u64`. +/// +/// The maximum number of digits is equal to the maximum number +/// of decimals (`u8::MAX`) plus the length of the decimal point +/// and the leading zero. +const MAX_FORMATTED_DIGITS: usize = u8::MAX as usize + 2; /// Checks that the account is owned by the expected program. #[inline(always)] @@ -146,16 +150,16 @@ fn try_ui_amount_into_amount(ui_amount: &str, decimals: u8) -> Result decimals - || (length + expected_after_decimal_length) > MAX_DIGITS_U64 + || (length + expected_after_decimal_length) > MAX_FORMATTED_DIGITS { return Err(ProgramError::InvalidArgument); } - let mut digits = [UNINIT_BYTE; MAX_DIGITS_U64]; + let mut digits = [UNINIT_BYTE; MAX_FORMATTED_DIGITS]; // SAFETY: `digits` is an array of `MaybeUninit`, which has the same // memory layout as `u8`. let slice: &mut [u8] = - unsafe { from_raw_parts_mut(digits.as_mut_ptr() as *mut _, MAX_DIGITS_U64) }; + unsafe { from_raw_parts_mut(digits.as_mut_ptr() as *mut _, MAX_FORMATTED_DIGITS) }; // SAFETY: the total length of `amount_str` and `after_decimal` is less than // `MAX_DIGITS_U64`. From 7bc8588da467c91bfce50a8f584e638a278774fa Mon Sep 17 00:00:00 2001 From: febo Date: Wed, 4 Dec 2024 20:13:39 +0000 Subject: [PATCH 289/335] Use heapless entrypoint --- p-token/src/entrypoint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index f72845e..7994f5a 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -1,11 +1,11 @@ use pinocchio::{ - account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey, + account_info::AccountInfo, heapless_entrypoint, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; use crate::processor::*; -entrypoint!(process_instruction); +heapless_entrypoint!(process_instruction); /// Process an instruction. /// From 58001dbe824422555dbef7d7505baf6779668cc0 Mon Sep 17 00:00:00 2001 From: febo Date: Sat, 7 Dec 2024 01:40:09 +0000 Subject: [PATCH 290/335] Change crate type --- interface/Cargo.toml | 3 +++ interface/src/lib.rs | 2 +- p-token/tests/amount_to_ui_amount.rs | 7 +++---- p-token/tests/approve.rs | 7 +++---- p-token/tests/approve_checked.rs | 7 +++---- p-token/tests/burn.rs | 7 +++---- p-token/tests/burn_checked.rs | 7 +++---- p-token/tests/close_account.rs | 7 +++---- p-token/tests/freeze_account.rs | 7 +++---- p-token/tests/initialize_account.rs | 7 +++---- p-token/tests/initialize_account2.rs | 7 +++---- p-token/tests/initialize_account3.rs | 7 +++---- p-token/tests/initialize_mint.rs | 8 +++++--- p-token/tests/initialize_mint2.rs | 8 +++++--- p-token/tests/initialize_multisig.rs | 8 +++++--- p-token/tests/initialize_multisig2.rs | 8 +++++--- p-token/tests/mint_to.rs | 7 +++---- p-token/tests/mint_to_checked.rs | 7 +++---- p-token/tests/revoke.rs | 7 +++---- p-token/tests/set_authority.rs | 7 +++---- p-token/tests/setup/mod.rs | 4 ++++ p-token/tests/thaw_account.rs | 7 +++---- p-token/tests/transfer.rs | 7 +++---- p-token/tests/transfer_checked.rs | 7 +++---- p-token/tests/ui_amount_to_amount.rs | 7 +++---- 25 files changed, 82 insertions(+), 85 deletions(-) diff --git a/interface/Cargo.toml b/interface/Cargo.toml index fb26855..ab63d2e 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -7,6 +7,9 @@ license = { workspace = true } repository = { workspace = true } publish = false +[lib] +crate-type = ["rlib"] + [dependencies] pinocchio = { workspace = true } pinocchio-pubkey = { workspace = true } diff --git a/interface/src/lib.rs b/interface/src/lib.rs index 47c701c..0d87f14 100644 --- a/interface/src/lib.rs +++ b/interface/src/lib.rs @@ -4,5 +4,5 @@ pub mod native_mint; pub mod state; pub mod program { - pinocchio_pubkey::declare_id!("11111111111111111111111111111111"); + pinocchio_pubkey::declare_id!("PToken1111111111111111111111111111111111111"); } diff --git a/p-token/tests/amount_to_ui_amount.rs b/p-token/tests/amount_to_ui_amount.rs index 463061a..e7cc8f6 100644 --- a/p-token/tests/amount_to_ui_amount.rs +++ b/p-token/tests/amount_to_ui_amount.rs @@ -2,16 +2,15 @@ mod setup; -use setup::mint; +use setup::{mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn amount_to_ui_amount(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/approve.rs b/p-token/tests/approve.rs index 4319b14..37ba3bf 100644 --- a/p-token/tests/approve.rs +++ b/p-token/tests/approve.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn approve(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs index 8320572..edd949b 100644 --- a/p-token/tests/approve_checked.rs +++ b/p-token/tests/approve_checked.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn approve_checked(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/burn.rs b/p-token/tests/burn.rs index baa12a9..57ced7b 100644 --- a/p-token/tests/burn.rs +++ b/p-token/tests/burn.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn burn(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/burn_checked.rs b/p-token/tests/burn_checked.rs index d53e21b..a9a05b1 100644 --- a/p-token/tests/burn_checked.rs +++ b/p-token/tests/burn_checked.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn burn_checked(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/close_account.rs b/p-token/tests/close_account.rs index a1633b3..3378432 100644 --- a/p-token/tests/close_account.rs +++ b/p-token/tests/close_account.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ pubkey::Pubkey, @@ -11,11 +11,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn close_account(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/freeze_account.rs b/p-token/tests/freeze_account.rs index 5883c20..2f44d46 100644 --- a/p-token/tests/freeze_account.rs +++ b/p-token/tests/freeze_account.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -13,11 +13,10 @@ use solana_sdk::{ use spl_token::state::AccountState; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn freeze_account(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs index bf23bec..9bbea2e 100644 --- a/p-token/tests/initialize_account.rs +++ b/p-token/tests/initialize_account.rs @@ -2,7 +2,7 @@ mod setup; -use setup::mint; +use setup::{mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -13,11 +13,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_account2.rs b/p-token/tests/initialize_account2.rs index 8eff530..7ed0aec 100644 --- a/p-token/tests/initialize_account2.rs +++ b/p-token/tests/initialize_account2.rs @@ -2,7 +2,7 @@ mod setup; -use setup::mint; +use setup::{mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -13,11 +13,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account2(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_account3.rs b/p-token/tests/initialize_account3.rs index 795c42a..74cf2df 100644 --- a/p-token/tests/initialize_account3.rs +++ b/p-token/tests/initialize_account3.rs @@ -2,7 +2,7 @@ mod setup; -use setup::mint; +use setup::{mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -13,11 +13,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account3(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 694ad64..f99ade1 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -1,7 +1,10 @@ #![cfg(feature = "test-sbf")] +mod setup; + use std::mem::size_of; +use setup::TOKEN_PROGRAM_ID; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_option::COption, @@ -14,11 +17,10 @@ use solana_sdk::{ use token_interface::state::mint::Mint; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index e5bf6e3..1b8c24f 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -1,7 +1,10 @@ #![cfg(feature = "test-sbf")] +mod setup; + use std::mem::size_of; +use setup::TOKEN_PROGRAM_ID; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_option::COption, @@ -14,11 +17,10 @@ use solana_sdk::{ use token_interface::state::mint::Mint; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint2(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 39fd6b9..574554d 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -1,5 +1,8 @@ #![cfg(feature = "test-sbf")] +mod setup; + +use setup::TOKEN_PROGRAM_ID; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -11,11 +14,10 @@ use solana_sdk::{ use spl_token::state::Multisig; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index f8427b5..e1d95b8 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -1,5 +1,8 @@ #![cfg(feature = "test-sbf")] +mod setup; + +use setup::TOKEN_PROGRAM_ID; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -11,11 +14,10 @@ use solana_sdk::{ use spl_token::state::Multisig; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig2(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index e343fb7..f735d2e 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn mint_to(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs index c6ecf54..cd126a5 100644 --- a/p-token/tests/mint_to_checked.rs +++ b/p-token/tests/mint_to_checked.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn mint_to_checked(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/revoke.rs b/p-token/tests/revoke.rs index ebdca5e..2760dbf 100644 --- a/p-token/tests/revoke.rs +++ b/p-token/tests/revoke.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn revoke(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/set_authority.rs b/p-token/tests/set_authority.rs index 4718564..2e37d7d 100644 --- a/p-token/tests/set_authority.rs +++ b/p-token/tests/set_authority.rs @@ -2,7 +2,7 @@ mod setup; -use setup::mint; +use setup::{mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_option::COption, @@ -14,11 +14,10 @@ use solana_sdk::{ use spl_token::instruction::AuthorityType; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn set_authority(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/setup/mod.rs b/p-token/tests/setup/mod.rs index 4ef329a..e79b8ce 100644 --- a/p-token/tests/setup/mod.rs +++ b/p-token/tests/setup/mod.rs @@ -1,4 +1,8 @@ +use solana_sdk::pubkey::Pubkey; + #[allow(dead_code)] pub mod account; #[allow(dead_code)] pub mod mint; + +pub const TOKEN_PROGRAM_ID: Pubkey = Pubkey::new_from_array(token_interface::program::ID); diff --git a/p-token/tests/thaw_account.rs b/p-token/tests/thaw_account.rs index 833459c..6ddae1a 100644 --- a/p-token/tests/thaw_account.rs +++ b/p-token/tests/thaw_account.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -13,11 +13,10 @@ use solana_sdk::{ use spl_token::state::AccountState; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn thaw_account(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index 70e56b4..ae7413e 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn transfer(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs index b4c2865..991a103 100644 --- a/p-token/tests/transfer_checked.rs +++ b/p-token/tests/transfer_checked.rs @@ -2,7 +2,7 @@ mod setup; -use setup::{account, mint}; +use setup::{account, mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{ program_pack::Pack, @@ -12,11 +12,10 @@ use solana_sdk::{ }; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn transfer_checked(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/ui_amount_to_amount.rs b/p-token/tests/ui_amount_to_amount.rs index e104c58..45843fb 100644 --- a/p-token/tests/ui_amount_to_amount.rs +++ b/p-token/tests/ui_amount_to_amount.rs @@ -2,16 +2,15 @@ mod setup; -use setup::mint; +use setup::{mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; #[test_case::test_case(spl_token::ID ; "spl-token")] -#[test_case::test_case(Pubkey::new_from_array(token_program::ID) ; "p-token")] +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn ui_amount_to_amount(token_program: Pubkey) { - let program_id = Pubkey::new_from_array(token_program::ID); - let mut context = ProgramTest::new("token_program", program_id, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; From c2f1c0e78d9ee3fa3559baef906b1e8a56d03002 Mon Sep 17 00:00:00 2001 From: febo Date: Sat, 7 Dec 2024 01:42:23 +0000 Subject: [PATCH 291/335] Update git dependency --- p-token/Cargo.toml | 2 +- p-token/src/entrypoint.rs | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 0351298..0ef9320 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -11,7 +11,7 @@ publish = false program-id = "PToken1111111111111111111111111111111111111" [lib] -crate-type = ["cdylib", "lib"] +crate-type = ["cdylib"] [features] logging = [] diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 7994f5a..0780829 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -1,11 +1,15 @@ use pinocchio::{ - account_info::AccountInfo, heapless_entrypoint, program_error::ProgramError, pubkey::Pubkey, - ProgramResult, + account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint, + program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; use crate::processor::*; -heapless_entrypoint!(process_instruction); +program_entrypoint!(process_instruction); +// Do not allocate memory. +no_allocator!(); +// Use the default panic handler. +default_panic_handler!(); /// Process an instruction. /// From 8263275749d0482ee10f51aee552393d00277b9b Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 24 Dec 2024 12:13:24 +0000 Subject: [PATCH 292/335] Fix account owner check --- p-token/src/processor/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index ae96986..051d62d 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -102,7 +102,7 @@ fn validate_owner( return Err(TokenError::OwnerMismatch.into()); } - if owner_account_info.data_len() == Multisig::LEN && &crate::ID != owner_account_info.owner() { + if owner_account_info.data_len() == Multisig::LEN && &crate::ID == owner_account_info.owner() { let multisig = unsafe { load::(owner_account_info.borrow_data_unchecked())? }; let mut num_signers = 0; From 285223a72757e4ec87df9bcb7db4a3da5c7e56dc Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 9 Jan 2025 02:30:40 +0000 Subject: [PATCH 293/335] Remove unnecessary mut --- p-token/tests/initialize_mint.rs | 2 +- p-token/tests/initialize_mint2.rs | 2 +- p-token/tests/initialize_multisig.rs | 2 +- p-token/tests/initialize_multisig2.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index f99ade1..4138446 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -20,7 +20,7 @@ use token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index 1b8c24f..50eafea 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -20,7 +20,7 @@ use token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint2(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 574554d..66fe40b 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -17,7 +17,7 @@ use spl_token::state::Multisig; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index e1d95b8..2745518 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -17,7 +17,7 @@ use spl_token::state::Multisig; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig2(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; From 31fc2c4dbb9afe62c9fca21be7d7b75c04acba17 Mon Sep 17 00:00:00 2001 From: febo Date: Sun, 12 Jan 2025 01:02:20 +0000 Subject: [PATCH 294/335] Update pinocchio dependency --- p-token/tests/initialize_mint.rs | 2 +- p-token/tests/initialize_mint2.rs | 2 +- p-token/tests/initialize_multisig.rs | 2 +- p-token/tests/initialize_multisig2.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 4138446..f99ade1 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -20,7 +20,7 @@ use token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint(token_program: Pubkey) { - let context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index 50eafea..1b8c24f 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -20,7 +20,7 @@ use token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint2(token_program: Pubkey) { - let context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 66fe40b..574554d 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -17,7 +17,7 @@ use spl_token::state::Multisig; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig(token_program: Pubkey) { - let context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index 2745518..e1d95b8 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -17,7 +17,7 @@ use spl_token::state::Multisig; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig2(token_program: Pubkey) { - let context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; From 1b184e6e4093b554605497b386a48ff561b32ea5 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 13:43:09 +0000 Subject: [PATCH 295/335] Add native amount setter --- interface/src/state/account.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index 65e8c69..0f0ba64 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -85,6 +85,11 @@ impl Account { self.is_native[0] == 1 } + #[inline(always)] + pub fn set_native_amount(&mut self, amount: u64) { + self.native_amount = amount.to_le_bytes(); + } + #[inline(always)] pub fn native_amount(&self) -> Option { if self.is_native() { From 0783ada5359474c8540c1dd6b2f9ebb0be14b768 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 13:44:24 +0000 Subject: [PATCH 296/335] Avoid unnecessary trim --- p-token/src/processor/amount_to_ui_amount.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 40fc13c..4ca5e3a 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -35,7 +35,7 @@ pub fn process_amount_to_ui_amount( // SAFETY: the logger is guaranteed to be a valid UTF-8 string. let mut s = unsafe { from_utf8_unchecked(&logger) }; - if mint.decimals > 0 { + if mint.decimals > 0 && s.contains('.') { let zeros_trimmed = s.trim_end_matches('0'); s = zeros_trimmed.trim_end_matches('.'); } From 1a85bad23f807a834f1d5854962105e2bf15be3d Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 13:45:52 +0000 Subject: [PATCH 297/335] Add result check --- p-token/src/processor/get_account_data_size.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index eb46a88..52c1e28 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -1,5 +1,6 @@ use pinocchio::{ - account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, + pubkey::Pubkey, ProgramResult, }; use token_interface::{ error::TokenError, @@ -9,16 +10,19 @@ use token_interface::{ use super::check_account_owner; #[inline(always)] -pub fn process_get_account_data_size(accounts: &[AccountInfo]) -> ProgramResult { +pub fn process_get_account_data_size( + program_id: &Pubkey, + accounts: &[AccountInfo], +) -> ProgramResult { let [mint_info, _remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; // Make sure the mint is valid. - check_account_owner(mint_info)?; + check_account_owner(program_id, mint_info)?; let _ = unsafe { - load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint) + load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? }; set_return_data(&Account::LEN.to_le_bytes()); From 8e05e8d0d2e44d6772b4ffb6e78a8fc27a8238b7 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 13:48:56 +0000 Subject: [PATCH 298/335] Map error --- p-token/src/processor/ui_amount_to_amount.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index 752386e..b7299dc 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -2,7 +2,10 @@ use core::str::from_utf8; use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; -use token_interface::state::{load, mint::Mint}; +use token_interface::{ + error::TokenError, + state::{load, mint::Mint}, +}; use super::{check_account_owner, try_ui_amount_into_amount}; @@ -17,7 +20,9 @@ pub fn process_ui_amount_to_amount( let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; // SAFETY: there is a single borrow to the `Mint` account. - let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; + let mint = unsafe { + load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? + }; let amount = try_ui_amount_into_amount(ui_amount, mint.decimals)?; set_return_data(&amount.to_le_bytes()); From 9e059bb3e18fffb27b207dff95eabf5b76f04a99 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 13:49:54 +0000 Subject: [PATCH 299/335] Set native amount --- p-token/src/processor/shared/initialize_account.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index d751a72..1a2c75f 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -77,6 +77,7 @@ pub fn process_initialize_account( if is_native_mint { account.set_native(true); + account.set_native_amount(minimum_balance); unsafe { account.set_amount( new_account_info From 04252cf23dc8d1a703d951d047992d5ff1b4f584 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 13:50:51 +0000 Subject: [PATCH 300/335] Use overflow error --- p-token/src/processor/shared/mint_to.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs index 7edd89e..62141bb 100644 --- a/p-token/src/processor/shared/mint_to.rs +++ b/p-token/src/processor/shared/mint_to.rs @@ -53,13 +53,13 @@ pub fn process_mint_to( let destination_amount = destination_account .amount() .checked_add(amount) - .ok_or(ProgramError::InvalidAccountData)?; + .ok_or(TokenError::Overflow)?; destination_account.set_amount(destination_amount); let mint_supply = mint .supply() .checked_add(amount) - .ok_or(ProgramError::InvalidAccountData)?; + .ok_or(TokenError::Overflow)?; mint.set_supply(mint_supply); } From fa0a2b7ae1716a9ac944d6f10f829819bafa6ccc Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 13:52:33 +0000 Subject: [PATCH 301/335] Update owner check --- p-token/src/processor/get_account_data_size.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index 52c1e28..ff2fa90 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -1,6 +1,5 @@ use pinocchio::{ - account_info::AccountInfo, program::set_return_data, program_error::ProgramError, - pubkey::Pubkey, ProgramResult, + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; use token_interface::{ error::TokenError, @@ -10,16 +9,13 @@ use token_interface::{ use super::check_account_owner; #[inline(always)] -pub fn process_get_account_data_size( - program_id: &Pubkey, - accounts: &[AccountInfo], -) -> ProgramResult { +pub fn process_get_account_data_size(accounts: &[AccountInfo]) -> ProgramResult { let [mint_info, _remaning @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; // Make sure the mint is valid. - check_account_owner(program_id, mint_info)?; + check_account_owner(mint_info)?; let _ = unsafe { load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? From befd42212e5f558224d83cf494228f8b28085eb6 Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 13:58:40 +0000 Subject: [PATCH 302/335] Update program id --- p-token/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p-token/src/lib.rs b/p-token/src/lib.rs index f19f387..6ee8c8d 100644 --- a/p-token/src/lib.rs +++ b/p-token/src/lib.rs @@ -5,4 +5,4 @@ mod entrypoint; mod processor; -pinocchio_pubkey::declare_id!("PToken1111111111111111111111111111111111111"); +pinocchio_pubkey::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); From 93adbecaff24fc83d2d9f77f7a1fd0bdd54d282a Mon Sep 17 00:00:00 2001 From: febo Date: Mon, 13 Jan 2025 15:03:57 +0000 Subject: [PATCH 303/335] Use interface program id --- interface/src/lib.rs | 2 +- p-token/src/lib.rs | 2 -- p-token/src/processor/mod.rs | 7 +++++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/lib.rs b/interface/src/lib.rs index 0d87f14..9622a25 100644 --- a/interface/src/lib.rs +++ b/interface/src/lib.rs @@ -4,5 +4,5 @@ pub mod native_mint; pub mod state; pub mod program { - pinocchio_pubkey::declare_id!("PToken1111111111111111111111111111111111111"); + pinocchio_pubkey::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); } diff --git a/p-token/src/lib.rs b/p-token/src/lib.rs index 6ee8c8d..0bd4439 100644 --- a/p-token/src/lib.rs +++ b/p-token/src/lib.rs @@ -4,5 +4,3 @@ mod entrypoint; mod processor; - -pinocchio_pubkey::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 051d62d..208a48e 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -10,6 +10,7 @@ use pinocchio::{ }; use token_interface::{ error::TokenError, + program::ID as TOKEN_PROGRAM_ID, state::{ load, multisig::{Multisig, MAX_SIGNERS}, @@ -84,7 +85,7 @@ const MAX_FORMATTED_DIGITS: usize = u8::MAX as usize + 2; /// Checks that the account is owned by the expected program. #[inline(always)] fn check_account_owner(account_info: &AccountInfo) -> ProgramResult { - if &crate::ID != account_info.owner() { + if &TOKEN_PROGRAM_ID != account_info.owner() { Err(ProgramError::IncorrectProgramId) } else { Ok(()) @@ -102,7 +103,9 @@ fn validate_owner( return Err(TokenError::OwnerMismatch.into()); } - if owner_account_info.data_len() == Multisig::LEN && &crate::ID == owner_account_info.owner() { + if owner_account_info.data_len() == Multisig::LEN + && owner_account_info.owner() == &TOKEN_PROGRAM_ID + { let multisig = unsafe { load::(owner_account_info.borrow_data_unchecked())? }; let mut num_signers = 0; From ba9856902b78741beea17a35f8d2dff7bcc20d5c Mon Sep 17 00:00:00 2001 From: febo Date: Thu, 23 Jan 2025 02:22:02 +0000 Subject: [PATCH 304/335] Add safety comments (#8) * Remove spl-token test cases * Update CU values * Add safety comments * Use git dependencies --- p-token/Cargo.toml | 1 - p-token/src/processor/amount_to_ui_amount.rs | 3 +- p-token/src/processor/burn_checked.rs | 30 ++++----- p-token/src/processor/close_account.rs | 48 ++++++++------ .../src/processor/get_account_data_size.rs | 2 + p-token/src/processor/initialize_account2.rs | 16 ++++- p-token/src/processor/initialize_account3.rs | 16 ++++- .../processor/initialize_immutable_owner.rs | 1 + p-token/src/processor/initialize_mint.rs | 10 ++- p-token/src/processor/mint_to_checked.rs | 27 ++++---- p-token/src/processor/mod.rs | 7 +- p-token/src/processor/revoke.rs | 2 + p-token/src/processor/set_authority.rs | 8 ++- p-token/src/processor/shared/approve.rs | 4 ++ p-token/src/processor/shared/burn.rs | 4 ++ .../processor/shared/initialize_account.rs | 8 ++- .../processor/shared/initialize_multisig.rs | 5 +- p-token/src/processor/shared/mint_to.rs | 4 ++ .../processor/shared/toggle_account_state.rs | 6 +- p-token/src/processor/shared/transfer.rs | 64 +++++++++++++------ p-token/src/processor/sync_native.rs | 2 + p-token/src/processor/transfer_checked.rs | 30 ++++----- p-token/src/processor/ui_amount_to_amount.rs | 3 +- p-token/tests/amount_to_ui_amount.rs | 1 - p-token/tests/approve.rs | 1 - p-token/tests/approve_checked.rs | 1 - p-token/tests/burn.rs | 1 - p-token/tests/burn_checked.rs | 1 - p-token/tests/close_account.rs | 1 - p-token/tests/freeze_account.rs | 1 - p-token/tests/initialize_account.rs | 1 - p-token/tests/initialize_account2.rs | 1 - p-token/tests/initialize_account3.rs | 1 - p-token/tests/initialize_mint.rs | 1 - p-token/tests/initialize_mint2.rs | 1 - p-token/tests/initialize_multisig.rs | 1 - p-token/tests/initialize_multisig2.rs | 1 - p-token/tests/mint_to.rs | 1 - p-token/tests/mint_to_checked.rs | 1 - p-token/tests/revoke.rs | 1 - p-token/tests/set_authority.rs | 1 - p-token/tests/thaw_account.rs | 1 - p-token/tests/transfer.rs | 1 - p-token/tests/transfer_checked.rs | 1 - p-token/tests/ui_amount_to_amount.rs | 1 - 45 files changed, 205 insertions(+), 118 deletions(-) diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 0ef9320..d527968 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -20,7 +20,6 @@ test-sbf = [] [dependencies] pinocchio = { workspace = true } pinocchio-log = { workspace = true } -pinocchio-pubkey = { workspace = true } token-interface = { version = "^0", path = "../interface" } [dev-dependencies] diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 4ca5e3a..6c13993 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -23,7 +23,8 @@ pub fn process_amount_to_ui_amount( let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; - // SAFETY: there is a single borrow to the `Mint` account. + // SAFETY: single immutable borrow to `mint_info` account data and + // `load` validates that the mint is initialized. let mint = unsafe { load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? }; diff --git a/p-token/src/processor/burn_checked.rs b/p-token/src/processor/burn_checked.rs index f9ef06c..88a745d 100644 --- a/p-token/src/processor/burn_checked.rs +++ b/p-token/src/processor/burn_checked.rs @@ -4,20 +4,20 @@ use super::shared; #[inline(always)] pub fn process_burn_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); - let amount = u64::from_le_bytes( - amount - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + // expected u64 (8) + u8 (1) + let (amount, decimals) = if instruction_data.len() == 9 { + let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + ( + u64::from_le_bytes( + amount + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ), + decimals.first(), + ) + } else { + return Err(ProgramError::InvalidInstructionData); + }; - shared::burn::process_burn( - accounts, - amount, - Some( - *decimals - .first() - .ok_or(ProgramError::InvalidInstructionData)?, - ), - ) + shared::burn::process_burn(accounts, amount, decimals.copied()) } diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs index ffd0263..3f90dea 100644 --- a/p-token/src/processor/close_account.rs +++ b/p-token/src/processor/close_account.rs @@ -3,14 +3,16 @@ use pinocchio::{ }; use token_interface::{ error::TokenError, - state::{account::Account, load_mut}, + state::{account::Account, load}, }; use super::validate_owner; -/// Incinerator address. -const INCINERATOR_ID: Pubkey = - pinocchio_pubkey::pubkey!("1nc1nerator11111111111111111111111111111111"); +/// Incinerator (`1nc1nerator11111111111111111111111111111111`) address. +const INCINERATOR_ID: Pubkey = [ + 0, 51, 144, 114, 141, 52, 17, 96, 121, 189, 201, 17, 191, 255, 0, 219, 212, 77, 46, 205, 204, + 247, 156, 166, 225, 0, 56, 225, 0, 0, 0, 0, +]; #[inline(always)] pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { @@ -24,26 +26,30 @@ pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { // raw pointer. if source_account_info == destination_account_info { return Err(ProgramError::InvalidAccountData); - } - - let source_account = - unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; - - if !source_account.is_native() && source_account.amount() != 0 { - return Err(TokenError::NonNativeHasBalance.into()); - } - - let authority = source_account - .close_authority() - .unwrap_or(&source_account.owner); - - if !source_account.is_owned_by_system_program_or_incinerator() { - validate_owner(authority, authority_info, remaining)?; - } else if destination_account_info.key() != &INCINERATOR_ID { - return Err(ProgramError::InvalidAccountData); + } else { + // SAFETY: scoped immutable borrow to `source_account_info` account data and + // `load` validates that the account is initialized. + let source_account = + unsafe { load::(source_account_info.borrow_data_unchecked())? }; + + if !source_account.is_native() && source_account.amount() != 0 { + return Err(TokenError::NonNativeHasBalance.into()); + } + + let authority = source_account + .close_authority() + .unwrap_or(&source_account.owner); + + if !source_account.is_owned_by_system_program_or_incinerator() { + validate_owner(authority, authority_info, remaining)?; + } else if destination_account_info.key() != &INCINERATOR_ID { + return Err(ProgramError::InvalidAccountData); + } } let destination_starting_lamports = destination_account_info.lamports(); + // SAFETY: single mutable borrow to `destination_account_info` lamports and + // there are no "active" borrows of `source_account_info` account data. unsafe { // Moves the lamports to the destination account. *destination_account_info.borrow_mut_lamports_unchecked() = destination_starting_lamports diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index ff2fa90..7693b64 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -17,6 +17,8 @@ pub fn process_get_account_data_size(accounts: &[AccountInfo]) -> ProgramResult // Make sure the mint is valid. check_account_owner(mint_info)?; + // SAFETY: single immutable borrow to `mint_info` account data and + // `load` validates that the mint is initialized. let _ = unsafe { load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? }; diff --git a/p-token/src/processor/initialize_account2.rs b/p-token/src/processor/initialize_account2.rs index 9200ee0..185c291 100644 --- a/p-token/src/processor/initialize_account2.rs +++ b/p-token/src/processor/initialize_account2.rs @@ -1,4 +1,9 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::{Pubkey, PUBKEY_BYTES}, + ProgramResult, +}; use super::shared; @@ -7,6 +12,13 @@ pub fn process_initialize_account2( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let owner = unsafe { &*(instruction_data.as_ptr() as *const Pubkey) }; + // SAFETY: validate `instruction_data` length. + let owner = unsafe { + if instruction_data.len() != PUBKEY_BYTES { + return Err(ProgramError::InvalidInstructionData); + } else { + &*(instruction_data.as_ptr() as *const Pubkey) + } + }; shared::initialize_account::process_initialize_account(accounts, Some(owner), true) } diff --git a/p-token/src/processor/initialize_account3.rs b/p-token/src/processor/initialize_account3.rs index 4eaa7a5..54e5501 100644 --- a/p-token/src/processor/initialize_account3.rs +++ b/p-token/src/processor/initialize_account3.rs @@ -1,4 +1,9 @@ -use pinocchio::{account_info::AccountInfo, pubkey::Pubkey, ProgramResult}; +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::{Pubkey, PUBKEY_BYTES}, + ProgramResult, +}; use super::shared; @@ -7,6 +12,13 @@ pub fn process_initialize_account3( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let owner = unsafe { &*(instruction_data.as_ptr() as *const Pubkey) }; + // SAFETY: validate `instruction_data` length. + let owner = unsafe { + if instruction_data.len() != PUBKEY_BYTES { + return Err(ProgramError::InvalidInstructionData); + } else { + &*(instruction_data.as_ptr() as *const Pubkey) + } + }; shared::initialize_account::process_initialize_account(accounts, Some(owner), false) } diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs index cf69da4..ba98c28 100644 --- a/p-token/src/processor/initialize_immutable_owner.rs +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -8,6 +8,7 @@ use token_interface::{ pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult { let token_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; + // SAFETY: single immutable borrow to `token_account_info` account data. let account = unsafe { load_unchecked::(token_account_info.borrow_data_unchecked())? }; if account.is_initialized() { diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 8460ce0..ee52eb4 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -35,6 +35,7 @@ pub fn process_initialize_mint( (mint_info, None) }; + // SAFETY: single mutable borrow to `mint_info` account data. let mint = unsafe { load_mut_unchecked::(mint_info.borrow_mut_data_unchecked())? }; if mint.is_initialized() { @@ -44,7 +45,9 @@ pub fn process_initialize_mint( // Check rent-exempt status of the mint account. let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { - let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are + // checked by `from_account_info_unchecked`. + let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; rent.is_exempt(mint_info.lamports(), size_of::()) } else { Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) @@ -81,7 +84,7 @@ impl InitializeMint<'_> { // - decimals (1 byte) // - mint_authority (32 bytes) // - option + freeze_authority (1 byte + 32 bytes) - if bytes.len() < 34 { + if bytes.len() < 34 || (bytes[33] == 1 && bytes.len() < 66) { return Err(ProgramError::InvalidInstructionData); } @@ -93,16 +96,19 @@ impl InitializeMint<'_> { #[inline] pub fn decimals(&self) -> u8 { + // SAFETY: the `bytes` length was validated in `try_from_bytes`. unsafe { *self.raw } } #[inline] pub fn mint_authority(&self) -> &Pubkey { + // SAFETY: the `bytes` length was validated in `try_from_bytes`. unsafe { &*(self.raw.add(1) as *const Pubkey) } } #[inline] pub fn freeze_authority(&self) -> Option<&Pubkey> { + // SAFETY: the `bytes` length was validated in `try_from_bytes`. unsafe { if *self.raw.add(33) == 0 { Option::None diff --git a/p-token/src/processor/mint_to_checked.rs b/p-token/src/processor/mint_to_checked.rs index 6fb3ae9..ebfcdea 100644 --- a/p-token/src/processor/mint_to_checked.rs +++ b/p-token/src/processor/mint_to_checked.rs @@ -4,17 +4,20 @@ use super::shared; #[inline(always)] pub fn process_mint_to_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + // expected u64 (8) + u8 (1) + let (amount, decimals) = if instruction_data.len() == 9 { + let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + ( + u64::from_le_bytes( + amount + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ), + decimals.first(), + ) + } else { + return Err(ProgramError::InvalidInstructionData); + }; - let amount = u64::from_le_bytes( - amount - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); - - shared::mint_to::process_mint_to( - accounts, - amount, - Some(*decimals.first().ok_or(ProgramError::InvalidAccountData)?), - ) + shared::mint_to::process_mint_to(accounts, amount, decimals.copied()) } diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 208a48e..0f0592f 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -92,7 +92,10 @@ fn check_account_owner(account_info: &AccountInfo) -> ProgramResult { } } -/// Validates owner(s) are present +/// Validates owner(s) are present. +/// +/// Note that `owner_account_info` will be immutable borrowed when it represents +/// a multisig account. #[inline(always)] fn validate_owner( expected_owner: &Pubkey, @@ -106,6 +109,8 @@ fn validate_owner( if owner_account_info.data_len() == Multisig::LEN && owner_account_info.owner() == &TOKEN_PROGRAM_ID { + // SAFETY: the caller guarantees that there are no mutable borrows of `owner_account_info` + // account data and the `load` validates that the account is initialized. let multisig = unsafe { load::(owner_account_info.borrow_data_unchecked())? }; let mut num_signers = 0; diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs index 2d40b02..6361d99 100644 --- a/p-token/src/processor/revoke.rs +++ b/p-token/src/processor/revoke.rs @@ -12,6 +12,8 @@ pub fn process_revoke(accounts: &[AccountInfo], _instruction_data: &[u8]) -> Pro return Err(ProgramError::NotEnoughAccountKeys); }; + // SAFETY: single mutable borrow to `source_account_info` account data and + // `load_mut` validates that the account is initialized. let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index 2b9fd94..3ad4d12 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -27,6 +27,8 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) }; if account_info.data_len() == Account::LEN { + // SAFETY: single mutable borrow to `account_info` account data and + // `load_mut` validates that the account is initialized. let account = unsafe { load_mut::(account_info.borrow_mut_data_unchecked())? }; if account.is_frozen() { @@ -65,6 +67,8 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) } } } else if account_info.data_len() == Mint::LEN { + // SAFETY: single mutable borrow to `account_info` account data and + // `load_mut` validates that the mint is initialized. let mint = unsafe { load_mut::(account_info.borrow_mut_data_unchecked())? }; match authority_type { @@ -119,7 +123,7 @@ impl SetAuthority<'_> { // The minimum expected size of the instruction data. // - authority_type (1 byte) // - option + new_authority (1 byte + 32 bytes) - if bytes.len() < 2 { + if bytes.len() < 2 || (bytes[1] == 1 && bytes.len() < 34) { return Err(ProgramError::InvalidInstructionData); } @@ -131,11 +135,13 @@ impl SetAuthority<'_> { #[inline(always)] pub fn authority_type(&self) -> Result { + // SAFETY: `bytes` length is validated in `try_from_bytes`. unsafe { AuthorityType::from(*self.raw) } } #[inline(always)] pub fn new_authority(&self) -> Option<&Pubkey> { + // SAFETY: `bytes` length is validated in `try_from_bytes`. unsafe { if *self.raw.add(1) == 0 { Option::None diff --git a/p-token/src/processor/shared/approve.rs b/p-token/src/processor/shared/approve.rs index 40fa7af..a9d2812 100644 --- a/p-token/src/processor/shared/approve.rs +++ b/p-token/src/processor/shared/approve.rs @@ -45,6 +45,8 @@ pub fn process_approve( // Validates source account. + // SAFETY: single mutable borrow to `source_account_info` account data and + // `load_mut` validates that the account is initialized. let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; @@ -57,6 +59,8 @@ pub fn process_approve( return Err(TokenError::MintMismatch.into()); } + // SAFETY: single immutable borrow of `mint_info` account data and + // `load` validates that the mint is initialized. let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; if expected_decimals != mint.decimals { diff --git a/p-token/src/processor/shared/burn.rs b/p-token/src/processor/shared/burn.rs index 1c26785..06f741a 100644 --- a/p-token/src/processor/shared/burn.rs +++ b/p-token/src/processor/shared/burn.rs @@ -16,6 +16,8 @@ pub fn process_burn( return Err(ProgramError::NotEnoughAccountKeys); }; + // SAFETY: single mutable borrow to `source_account_info` account data and + // `load_mut` validates that the account is initialized. let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; @@ -33,6 +35,8 @@ pub fn process_burn( .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; + // SAFETY: single mutable borrow to `mint_info` account data and + // `load_mut` validates that the mint is initialized. let mint = unsafe { load_mut::(mint_info.borrow_mut_data_unchecked())? }; if mint_info.key() != &source_account.mint { diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index 1a2c75f..952dd1f 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -42,7 +42,9 @@ pub fn process_initialize_account( let minimum_balance = if rent_sysvar_account { let rent_sysvar_info = remaning.first().ok_or(ProgramError::NotEnoughAccountKeys)?; - let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are + // checked by `from_account_info_unchecked`. + let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; rent.minimum_balance(new_account_info_data_len) } else { Rent::get()?.minimum_balance(new_account_info_data_len) @@ -52,6 +54,7 @@ pub fn process_initialize_account( // Initialize the account. + // SAFETY: single mutable borrow of the 'new_account_info' account data. let account = unsafe { load_mut_unchecked::(new_account_info.borrow_mut_data_unchecked())? }; @@ -66,6 +69,8 @@ pub fn process_initialize_account( if !is_native_mint { check_account_owner(mint_info)?; + // SAFETY: single immutable borrow of `mint_info` account data and + // `load` validates that the mint is initialized. let _ = unsafe { load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? }; @@ -78,6 +83,7 @@ pub fn process_initialize_account( if is_native_mint { account.set_native(true); account.set_native_amount(minimum_balance); + // SAFETY: single mutable borrow to `new_account_info` lamports. unsafe { account.set_amount( new_account_info diff --git a/p-token/src/processor/shared/initialize_multisig.rs b/p-token/src/processor/shared/initialize_multisig.rs index 8831c19..0d45fa8 100644 --- a/p-token/src/processor/shared/initialize_multisig.rs +++ b/p-token/src/processor/shared/initialize_multisig.rs @@ -32,12 +32,15 @@ pub fn process_initialize_multisig( let multisig_info_data_len = multisig_info.data_len(); let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { - let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) }; + // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are + // checked by `from_account_info_unchecked`. + let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) } else { Rent::get()?.is_exempt(multisig_info.lamports(), multisig_info_data_len) }; + // SAFETY: single mutable borrow to `multisig_info` account data. let multisig = unsafe { load_mut_unchecked::(multisig_info.borrow_mut_data_unchecked())? }; diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs index 62141bb..773039f 100644 --- a/p-token/src/processor/shared/mint_to.rs +++ b/p-token/src/processor/shared/mint_to.rs @@ -18,6 +18,8 @@ pub fn process_mint_to( // Validates the destination account. + // SAFETY: single mutable borrow to `destination_account_info` account data and + // `load_mut` validates that the account is initialized. let destination_account = unsafe { load_mut::(destination_account_info.borrow_mut_data_unchecked())? }; @@ -33,6 +35,8 @@ pub fn process_mint_to( return Err(TokenError::MintMismatch.into()); } + // SAFETY: single mutable borrow to `mint_info` account data and + // `load_mut` validates that the mint is initialized. let mint = unsafe { load_mut::(mint_info.borrow_mut_data_unchecked())? }; if let Some(expected_decimals) = expected_decimals { diff --git a/p-token/src/processor/shared/toggle_account_state.rs b/p-token/src/processor/shared/toggle_account_state.rs index bf05bfd..c9ff11a 100644 --- a/p-token/src/processor/shared/toggle_account_state.rs +++ b/p-token/src/processor/shared/toggle_account_state.rs @@ -12,10 +12,12 @@ pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> P return Err(ProgramError::NotEnoughAccountKeys); }; + // SAFETY: single mutable borrow to `source_account_info` account data and + // `load_mut` validates that the account is initialized. let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; - if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() { + if freeze == source_account.is_frozen() { return Err(TokenError::InvalidState.into()); } if source_account.is_native() { @@ -25,6 +27,8 @@ pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> P return Err(TokenError::MintMismatch.into()); } + // SAFETY: single immutable borrow of `mint_info` account data and + // `load` validates that the mint is initialized. let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; match mint.freeze_authority() { diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index 6d33d5f..aafd0a1 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -1,7 +1,7 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use token_interface::{ error::TokenError, - state::{account::Account, load, load_mut, mint::Mint}, + state::{account::Account, load, load_mut, load_mut_unchecked, mint::Mint}, }; use crate::processor::{check_account_owner, validate_owner}; @@ -51,27 +51,49 @@ pub fn process_transfer( // Validates source and destination accounts. + // SAFETY: single mutable borrow to `source_account_info` account data and + // `load_mut` validates that the account is initialized. let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; - let destination_account = - unsafe { load_mut::(destination_account_info.borrow_mut_data_unchecked())? }; - - if source_account.is_frozen() || destination_account.is_frozen() { - return Err(TokenError::AccountFrozen.into()); - } + // Comparing whether the AccountInfo's "point" to the same account or + // not - this is a faster comparison since it just checks the internal + // raw pointer. + let self_transfer = source_account_info == destination_account_info; // Implicitly validates that the account has enough tokens by calculating the // remaining amount - the amount is only updated on the account if the transfer // is successful. - let remaining_amount = source_account - .amount() - .checked_sub(amount) - .ok_or(TokenError::InsufficientFunds)?; + let remaining_amount = if self_transfer { + if source_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } - if source_account.mint != destination_account.mint { - return Err(TokenError::MintMismatch.into()); - } + source_account + .amount() + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)? + } else { + // SAFETY: scoped immutable borrow to `destination_account_info` account data and + // `load` validates that the account is initialized. + let destination_account = + unsafe { load::(destination_account_info.borrow_data_unchecked())? }; + + if source_account.is_frozen() || destination_account.is_frozen() { + return Err(TokenError::AccountFrozen.into()); + } + + let remaining_amount = source_account + .amount() + .checked_sub(amount) + .ok_or(TokenError::InsufficientFunds)?; + + if source_account.mint != destination_account.mint { + return Err(TokenError::MintMismatch.into()); + } + + remaining_amount + }; // Validates the mint information. @@ -80,6 +102,8 @@ pub fn process_transfer( return Err(TokenError::MintMismatch.into()); } + // SAFETY: single immutable borrow of `mint_info` account data and + // `load` validates that the mint is initialized. let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; if decimals != mint.decimals { @@ -87,11 +111,6 @@ pub fn process_transfer( } } - // Comparing whether the AccountInfo's "point" to the same account or - // not - this is a faster comparison since it just checks the internal - // raw pointer. - let self_transfer = source_account_info == destination_account_info; - // Validates the authority (delegate or owner). if source_account.delegate() == Some(authority_info.key()) { @@ -123,6 +142,11 @@ pub fn process_transfer( source_account.set_amount(remaining_amount); + // SAFETY: single mutable borrow to `destination_account_info` account data; the account + // is guaranteed to be initialized and different than `source_account_info`. + let destination_account = unsafe { + load_mut_unchecked::(destination_account_info.borrow_mut_data_unchecked())? + }; let destination_amount = destination_account .amount() .checked_add(amount) @@ -130,11 +154,13 @@ pub fn process_transfer( destination_account.set_amount(destination_amount); if source_account.is_native() { + // SAFETY: single mutable borrow to `source_account_info` lamports. let source_lamports = unsafe { source_account_info.borrow_mut_lamports_unchecked() }; *source_lamports = source_lamports .checked_sub(amount) .ok_or(TokenError::Overflow)?; + // SAFETY: single mutable borrow to `destination_account_info` lamports. let destination_lamports = unsafe { destination_account_info.borrow_mut_lamports_unchecked() }; *destination_lamports = destination_lamports diff --git a/p-token/src/processor/sync_native.rs b/p-token/src/processor/sync_native.rs index 9bba708..4ccc276 100644 --- a/p-token/src/processor/sync_native.rs +++ b/p-token/src/processor/sync_native.rs @@ -12,6 +12,8 @@ pub fn process_sync_native(accounts: &[AccountInfo]) -> ProgramResult { check_account_owner(native_account_info)?; + // SAFETY: single mutable borrow to `native_account_info` account data and + // `load_mut` validates that the account is initialized. let native_account = unsafe { load_mut::(native_account_info.borrow_mut_data_unchecked())? }; diff --git a/p-token/src/processor/transfer_checked.rs b/p-token/src/processor/transfer_checked.rs index 4c23ee5..ea75a28 100644 --- a/p-token/src/processor/transfer_checked.rs +++ b/p-token/src/processor/transfer_checked.rs @@ -7,20 +7,20 @@ pub fn process_transfer_checked( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); - let amount = u64::from_le_bytes( - amount - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + // expected u64 (8) + u8 (1) + let (amount, decimals) = if instruction_data.len() == 9 { + let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + ( + u64::from_le_bytes( + amount + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?, + ), + decimals.first(), + ) + } else { + return Err(ProgramError::InvalidInstructionData); + }; - shared::transfer::process_transfer( - accounts, - amount, - Some( - *decimals - .first() - .ok_or(ProgramError::InvalidInstructionData)?, - ), - ) + shared::transfer::process_transfer(accounts, amount, decimals.copied()) } diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index b7299dc..823ffbc 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -19,7 +19,8 @@ pub fn process_ui_amount_to_amount( let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; - // SAFETY: there is a single borrow to the `Mint` account. + // SAFETY: single immutable borrow to `mint_info` account data and + // `load` validates that the mint is initialized. let mint = unsafe { load::(mint_info.borrow_data_unchecked()).map_err(|_| TokenError::InvalidMint)? }; diff --git a/p-token/tests/amount_to_ui_amount.rs b/p-token/tests/amount_to_ui_amount.rs index e7cc8f6..402be08 100644 --- a/p-token/tests/amount_to_ui_amount.rs +++ b/p-token/tests/amount_to_ui_amount.rs @@ -6,7 +6,6 @@ use setup::{mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn amount_to_ui_amount(token_program: Pubkey) { diff --git a/p-token/tests/approve.rs b/p-token/tests/approve.rs index 37ba3bf..f3b28e2 100644 --- a/p-token/tests/approve.rs +++ b/p-token/tests/approve.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn approve(token_program: Pubkey) { diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs index edd949b..e34fa7a 100644 --- a/p-token/tests/approve_checked.rs +++ b/p-token/tests/approve_checked.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn approve_checked(token_program: Pubkey) { diff --git a/p-token/tests/burn.rs b/p-token/tests/burn.rs index 57ced7b..6e5e2e5 100644 --- a/p-token/tests/burn.rs +++ b/p-token/tests/burn.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn burn(token_program: Pubkey) { diff --git a/p-token/tests/burn_checked.rs b/p-token/tests/burn_checked.rs index a9a05b1..a008262 100644 --- a/p-token/tests/burn_checked.rs +++ b/p-token/tests/burn_checked.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn burn_checked(token_program: Pubkey) { diff --git a/p-token/tests/close_account.rs b/p-token/tests/close_account.rs index 3378432..8a73432 100644 --- a/p-token/tests/close_account.rs +++ b/p-token/tests/close_account.rs @@ -10,7 +10,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn close_account(token_program: Pubkey) { diff --git a/p-token/tests/freeze_account.rs b/p-token/tests/freeze_account.rs index 2f44d46..d5fb3af 100644 --- a/p-token/tests/freeze_account.rs +++ b/p-token/tests/freeze_account.rs @@ -12,7 +12,6 @@ use solana_sdk::{ }; use spl_token::state::AccountState; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn freeze_account(token_program: Pubkey) { diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs index 9bbea2e..4c491bb 100644 --- a/p-token/tests/initialize_account.rs +++ b/p-token/tests/initialize_account.rs @@ -12,7 +12,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account(token_program: Pubkey) { diff --git a/p-token/tests/initialize_account2.rs b/p-token/tests/initialize_account2.rs index 7ed0aec..9f250e4 100644 --- a/p-token/tests/initialize_account2.rs +++ b/p-token/tests/initialize_account2.rs @@ -12,7 +12,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account2(token_program: Pubkey) { diff --git a/p-token/tests/initialize_account3.rs b/p-token/tests/initialize_account3.rs index 74cf2df..7fee802 100644 --- a/p-token/tests/initialize_account3.rs +++ b/p-token/tests/initialize_account3.rs @@ -12,7 +12,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account3(token_program: Pubkey) { diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index f99ade1..175e805 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -16,7 +16,6 @@ use solana_sdk::{ }; use token_interface::state::mint::Mint; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint(token_program: Pubkey) { diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index 1b8c24f..683e1e3 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -16,7 +16,6 @@ use solana_sdk::{ }; use token_interface::state::mint::Mint; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint2(token_program: Pubkey) { diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 574554d..5cf9e34 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -13,7 +13,6 @@ use solana_sdk::{ }; use spl_token::state::Multisig; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig(token_program: Pubkey) { diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index e1d95b8..443a988 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -13,7 +13,6 @@ use solana_sdk::{ }; use spl_token::state::Multisig; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig2(token_program: Pubkey) { diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index f735d2e..9cafae3 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn mint_to(token_program: Pubkey) { diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs index cd126a5..1d0cb72 100644 --- a/p-token/tests/mint_to_checked.rs +++ b/p-token/tests/mint_to_checked.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn mint_to_checked(token_program: Pubkey) { diff --git a/p-token/tests/revoke.rs b/p-token/tests/revoke.rs index 2760dbf..689c48c 100644 --- a/p-token/tests/revoke.rs +++ b/p-token/tests/revoke.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn revoke(token_program: Pubkey) { diff --git a/p-token/tests/set_authority.rs b/p-token/tests/set_authority.rs index 2e37d7d..977d22e 100644 --- a/p-token/tests/set_authority.rs +++ b/p-token/tests/set_authority.rs @@ -13,7 +13,6 @@ use solana_sdk::{ }; use spl_token::instruction::AuthorityType; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn set_authority(token_program: Pubkey) { diff --git a/p-token/tests/thaw_account.rs b/p-token/tests/thaw_account.rs index 6ddae1a..6fe5762 100644 --- a/p-token/tests/thaw_account.rs +++ b/p-token/tests/thaw_account.rs @@ -12,7 +12,6 @@ use solana_sdk::{ }; use spl_token::state::AccountState; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn thaw_account(token_program: Pubkey) { diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index ae7413e..16491c2 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn transfer(token_program: Pubkey) { diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs index 991a103..d03c9f5 100644 --- a/p-token/tests/transfer_checked.rs +++ b/p-token/tests/transfer_checked.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn transfer_checked(token_program: Pubkey) { diff --git a/p-token/tests/ui_amount_to_amount.rs b/p-token/tests/ui_amount_to_amount.rs index 45843fb..3b1a6db 100644 --- a/p-token/tests/ui_amount_to_amount.rs +++ b/p-token/tests/ui_amount_to_amount.rs @@ -6,7 +6,6 @@ use setup::{mint, TOKEN_PROGRAM_ID}; use solana_program_test::{tokio, ProgramTest}; use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; -#[test_case::test_case(spl_token::ID ; "spl-token")] #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn ui_amount_to_amount(token_program: Pubkey) { From 08aa3ccecb30692bca18d6f927804337de82d5ff Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Wed, 5 Feb 2025 17:25:05 +0000 Subject: [PATCH 305/335] p-token: Fix typo (#23) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix typo Co-authored-by: Dean 利迪恩 --- p-token/src/processor/get_account_data_size.rs | 2 +- p-token/src/processor/revoke.rs | 4 ++-- p-token/src/processor/set_authority.rs | 10 +++++----- p-token/src/processor/shared/approve.rs | 8 ++++---- p-token/src/processor/shared/initialize_account.rs | 14 ++++++++------ p-token/src/processor/shared/transfer.rs | 14 +++++++------- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index 7693b64..0131b48 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -10,7 +10,7 @@ use super::check_account_owner; #[inline(always)] pub fn process_get_account_data_size(accounts: &[AccountInfo]) -> ProgramResult { - let [mint_info, _remaning @ ..] = accounts else { + let [mint_info, _remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs index 6361d99..50b01dd 100644 --- a/p-token/src/processor/revoke.rs +++ b/p-token/src/processor/revoke.rs @@ -8,7 +8,7 @@ use super::validate_owner; #[inline(always)] pub fn process_revoke(accounts: &[AccountInfo], _instruction_data: &[u8]) -> ProgramResult { - let [source_account_info, owner_info, remaning @ ..] = accounts else { + let [source_account_info, owner_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; @@ -21,7 +21,7 @@ pub fn process_revoke(accounts: &[AccountInfo], _instruction_data: &[u8]) -> Pro return Err(TokenError::AccountFrozen.into()); } - validate_owner(&source_account.owner, owner_info, remaning)?; + validate_owner(&source_account.owner, owner_info, remaining)?; source_account.clear_delegate(); source_account.set_delegated_amount(0); diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index 3ad4d12..fcfa9f1 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -22,7 +22,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) // Validates the accounts. - let [account_info, authority_info, remaning @ ..] = accounts else { + let [account_info, authority_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; @@ -37,7 +37,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) match authority_type { AuthorityType::AccountOwner => { - validate_owner(&account.owner, authority_info, remaning)?; + validate_owner(&account.owner, authority_info, remaining)?; if let Some(authority) = new_authority { account.owner = *authority; @@ -54,7 +54,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) } AuthorityType::CloseAccount => { let authority = account.close_authority().unwrap_or(&account.owner); - validate_owner(authority, authority_info, remaning)?; + validate_owner(authority, authority_info, remaining)?; if let Some(authority) = new_authority { account.set_close_authority(authority); @@ -77,7 +77,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) // mint_authority. let mint_authority = mint.mint_authority().ok_or(TokenError::FixedSupply)?; - validate_owner(mint_authority, authority_info, remaning)?; + validate_owner(mint_authority, authority_info, remaining)?; if let Some(authority) = new_authority { mint.set_mint_authority(authority); @@ -92,7 +92,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) .freeze_authority() .ok_or(TokenError::MintCannotFreeze)?; - validate_owner(freeze_authority, authority_info, remaning)?; + validate_owner(freeze_authority, authority_info, remaining)?; if let Some(authority) = new_authority { mint.set_freeze_authority(authority); diff --git a/p-token/src/processor/shared/approve.rs b/p-token/src/processor/shared/approve.rs index a9d2812..d5e90d5 100644 --- a/p-token/src/processor/shared/approve.rs +++ b/p-token/src/processor/shared/approve.rs @@ -17,7 +17,7 @@ pub fn process_approve( let (source_account_info, expected_mint_info, delegate_info, owner_info, remaining) = if let Some(expected_decimals) = expected_decimals { - let [source_account_info, expected_mint_info, delegate_info, owner_info, remaning @ ..] = + let [source_account_info, expected_mint_info, delegate_info, owner_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -28,10 +28,10 @@ pub fn process_approve( Some((expected_mint_info, expected_decimals)), delegate_info, owner_info, - remaning, + remaining, ) } else { - let [source_account_info, delegate_info, owner_info, remaning @ ..] = accounts else { + let [source_account_info, delegate_info, owner_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; ( @@ -39,7 +39,7 @@ pub fn process_approve( None, delegate_info, owner_info, - remaning, + remaining, ) }; diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index 952dd1f..796e82e 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -24,16 +24,16 @@ pub fn process_initialize_account( ) -> ProgramResult { // Accounts expected depend on whether we have the `rent_sysvar` account or not. - let (new_account_info, mint_info, owner, remaning) = if let Some(owner) = owner { - let [new_account_info, mint_info, remaning @ ..] = accounts else { + let (new_account_info, mint_info, owner, remaining) = if let Some(owner) = owner { + let [new_account_info, mint_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - (new_account_info, mint_info, owner, remaning) + (new_account_info, mint_info, owner, remaining) } else { - let [new_account_info, mint_info, owner_info, remaning @ ..] = accounts else { + let [new_account_info, mint_info, owner_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - (new_account_info, mint_info, owner_info.key(), remaning) + (new_account_info, mint_info, owner_info.key(), remaining) }; // Check rent-exempt status of the token account. @@ -41,7 +41,9 @@ pub fn process_initialize_account( let new_account_info_data_len = new_account_info.data_len(); let minimum_balance = if rent_sysvar_account { - let rent_sysvar_info = remaning.first().ok_or(ProgramError::NotEnoughAccountKeys)?; + let rent_sysvar_info = remaining + .first() + .ok_or(ProgramError::NotEnoughAccountKeys)?; // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are // checked by `from_account_info_unchecked`. let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index aafd0a1..c71a5af 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -20,9 +20,9 @@ pub fn process_transfer( expected_mint_info, destination_account_info, authority_info, - remaning, + remaining, ) = if let Some(decimals) = expected_decimals { - let [source_account_info, mint_info, destination_account_info, authority_info, remaning @ ..] = + let [source_account_info, mint_info, destination_account_info, authority_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -32,10 +32,10 @@ pub fn process_transfer( Some((mint_info, decimals)), destination_account_info, authority_info, - remaning, + remaining, ) } else { - let [source_account_info, destination_account_info, authority_info, remaning @ ..] = + let [source_account_info, destination_account_info, authority_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -45,7 +45,7 @@ pub fn process_transfer( None, destination_account_info, authority_info, - remaning, + remaining, ) }; @@ -114,7 +114,7 @@ pub fn process_transfer( // Validates the authority (delegate or owner). if source_account.delegate() == Some(authority_info.key()) { - validate_owner(authority_info.key(), authority_info, remaning)?; + validate_owner(authority_info.key(), authority_info, remaining)?; let delegated_amount = source_account .delegated_amount() @@ -129,7 +129,7 @@ pub fn process_transfer( } } } else { - validate_owner(&source_account.owner, authority_info, remaning)?; + validate_owner(&source_account.owner, authority_info, remaining)?; } if self_transfer || amount == 0 { From 6d18ff73b1dd30703a30b1ca941cb0f1d18c2b2a Mon Sep 17 00:00:00 2001 From: Kevin Heavey Date: Wed, 26 Feb 2025 18:19:49 +0400 Subject: [PATCH 306/335] remove solana-program from program/src (#26) * remove solana-program from program/src * fmt * use updated mollusk fork * switch to published mollusk * fix import in tests * add sdk to solana.dic --- Cargo.lock | 1356 +++++++++++++++++++++++++++++------- program/Cargo.toml | 21 +- program/src/entrypoint.rs | 9 +- program/src/error.rs | 8 +- program/src/instruction.rs | 12 +- program/src/lib.rs | 33 +- program/src/native_mint.rs | 4 +- program/src/processor.rs | 31 +- program/src/state.rs | 14 +- program/tests/processor.rs | 12 +- scripts/solana.dic | 1 + 11 files changed, 1187 insertions(+), 314 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71bb79d..b5bf87d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -335,11 +336,11 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb65153674e51d3a42c8f27b05b9508cea85edfaade8aa46bc8fc18cecdfef3" +checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc" dependencies = [ - "borsh-derive 1.5.4", + "borsh-derive 1.5.5", "cfg_aliases", ] @@ -358,9 +359,9 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a396e17ad94059c650db3d253bb6e25927f1eb462eede7e7a153bb6e75dce0a7" +checksum = "f8b668d39970baad5356d7c83a86fee3a539e6f93bf6764c97368243e17a0487" dependencies = [ "once_cell", "proc-macro-crate 3.2.0", @@ -404,9 +405,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -465,9 +466,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" [[package]] name = "cc" @@ -1010,7 +1011,6 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "serde", "typenum", "version_check", ] @@ -1163,9 +1163,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "httpdate" @@ -1374,9 +1374,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "itertools" @@ -1553,9 +1553,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" dependencies = [ "adler2", ] @@ -1573,37 +1573,62 @@ dependencies = [ [[package]] name = "mollusk-svm" -version = "0.0.13" -source = "git+https://github.com/buffalojoec/mollusk.git#ba391d116e8a032806cb093e7433940fa2cf27b6" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd69eeb49efb56a6da89cb095260d327ed585031c1d9f7c2aa70633621e1d2e" dependencies = [ "bincode", "mollusk-svm-error", "mollusk-svm-keys", + "solana-account", "solana-bpf-loader-program", + "solana-clock", "solana-compute-budget", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-feature-set", + "solana-fee-structure", + "solana-hash", + "solana-instruction", + "solana-loader-v3-interface", + "solana-log-collector", "solana-logger", + "solana-precompiles", + "solana-program-error", "solana-program-runtime", - "solana-sdk", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-stake-interface", "solana-system-program", + "solana-sysvar", + "solana-sysvar-id", "solana-timings", + "solana-transaction-context", ] [[package]] name = "mollusk-svm-error" -version = "0.0.13" -source = "git+https://github.com/buffalojoec/mollusk.git#ba391d116e8a032806cb093e7433940fa2cf27b6" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c8d71e29fb7e0047f3cffec055bc931011a7abfa3c1954fb18612d28a7c1f9" dependencies = [ - "solana-sdk", + "solana-pubkey", "thiserror 1.0.69", ] [[package]] name = "mollusk-svm-keys" -version = "0.0.13" -source = "git+https://github.com/buffalojoec/mollusk.git#ba391d116e8a032806cb093e7433940fa2cf27b6" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c08779697eeb0a288ec9338edf8b7a74417818aaef11fdadb5ebb0a3fe9075b" dependencies = [ "mollusk-svm-error", - "solana-sdk", + "solana-account", + "solana-instruction", + "solana-pubkey", + "solana-transaction-context", ] [[package]] @@ -1919,6 +1944,17 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "qualifier_attr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -2097,15 +2133,14 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" dependencies = [ "cc", "cfg-if", "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -2208,12 +2243,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scroll" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" - [[package]] name = "sct" version = "0.7.1" @@ -2245,6 +2274,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.15" @@ -2267,9 +2305,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", @@ -2416,23 +2454,27 @@ dependencies = [ [[package]] name = "solana-account" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb7cd6b50247886f9ef190d14896c85a4337fe0e648a9aba162a0b2d283cae2" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" dependencies = [ "bincode", "serde", "serde_bytes", "serde_derive", + "solana-account-info", + "solana-clock", "solana-instruction", - "solana-program", + "solana-pubkey", + "solana-sdk-ids", + "solana-sysvar", ] [[package]] name = "solana-account-info" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e053b991f91fd274df53e070c77a0a6a33681a5102c6421a0ca9ffaa0040368a" +checksum = "e0c17d606a298a205fae325489fbed88ee6dc4463c111672172327e741c8905d" dependencies = [ "bincode", "serde", @@ -2441,104 +2483,222 @@ dependencies = [ "solana-pubkey", ] +[[package]] +name = "solana-address-lookup-table-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-slot-hashes", +] + [[package]] name = "solana-atomic-u64" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "966dce88672728380c476d5d3e54c02025875100b8246db05669961806c9575e" +checksum = "d52e52720efe60465b052b9e7445a01c17550666beec855cce66f44766697bc2" dependencies = [ "parking_lot", ] +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall", +] + [[package]] name = "solana-bincode" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117b9646b1e9e6c4b48f363ad4c5af25c4ab35754ff307714e5fec2c3c4bb6b" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" dependencies = [ "bincode", "serde", "solana-instruction", ] +[[package]] +name = "solana-blake3-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" +dependencies = [ + "blake3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + [[package]] name = "solana-bn254" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12227c0e89785367be826b51452807c36f31c4f25cf8891da259b699e0de882d" +checksum = "9abc69625158faaab02347370b91c0d8e0fe347bf9287239f0fbe8f5864d91da" dependencies = [ "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", "bytemuck", - "solana-program", - "thiserror 1.0.69", + "solana-define-syscall", + "thiserror 2.0.11", ] [[package]] name = "solana-borsh" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c55b83c305eac62095b6f24ea2ae729f17de47e5a4e866ee4ddd0dc501b351e" +checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" dependencies = [ "borsh 0.10.4", - "borsh 1.5.4", + "borsh 1.5.5", ] [[package]] name = "solana-bpf-loader-program" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd37acbbdf0c188f74031a144b233f266ed124f3e45c2d24578b1fd5e14a62bb" +checksum = "f452bd2217eb46f24a828c7408c9e4fef2cc1767656560ca26006e20febf4068" dependencies = [ "bincode", - "byteorder", "libsecp256k1", - "log", + "qualifier_attr", "scopeguard", + "solana-account", + "solana-account-info", + "solana-big-mod-exp", + "solana-bincode", + "solana-blake3-hasher", "solana-bn254", + "solana-clock", "solana-compute-budget", + "solana-cpi", "solana-curve25519", "solana-feature-set", + "solana-hash", + "solana-instruction", + "solana-keccak-hasher", + "solana-loader-v3-interface", "solana-log-collector", "solana-measure", + "solana-packet", "solana-poseidon", + "solana-precompiles", + "solana-program-entrypoint", "solana-program-memory", "solana-program-runtime", - "solana-sdk", + "solana-pubkey", + "solana-sbpf", + "solana-sdk-ids", + "solana-secp256k1-recover", + "solana-sha256-hasher", + "solana-stable-layout", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", "solana-timings", + "solana-transaction-context", "solana-type-overrides", - "solana_rbpf", - "thiserror 1.0.69", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-client-traits" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83f0071874e629f29e0eb3dab8a863e98502ac7aba55b7e0df1803fc5cac72a7" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction", + "solana-transaction-error", ] [[package]] name = "solana-clock" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2387b936492cab0649c2a3e3fcfb282077029b533fa8454c88c41dff3bc2552" +checksum = "67c2177a1b9fe8326004f1151a5acd124420b737811080b1035df31349e4d892" dependencies = [ "serde", "serde_derive", + "solana-sdk-ids", "solana-sdk-macro", "solana-sysvar-id", ] +[[package]] +name = "solana-cluster-type" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ace9fea2daa28354d107ea879cff107181d85cd4e0f78a2bedb10e1a428c97e" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", +] + +[[package]] +name = "solana-commitment-config" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac49c4dde3edfa832de1697e9bcdb7c3b3f7cb7a1981b7c62526c8bb6700fb73" +dependencies = [ + "serde", + "serde_derive", +] + [[package]] name = "solana-compute-budget" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c3a791445139e208e83fde5ddfcbde462f7b90bd21fe8888b8f7d7863af9af" +checksum = "57e9b1dc0a5a63ea68e08ff2cac13c92e86cfe8e6c31421dd795e8c3df78de39" dependencies = [ - "solana-sdk", + "solana-fee-structure", + "solana-program-entrypoint", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5df17b195d312b66dccdde9beec6709766d8230cb4718c4c08854f780d0309" +dependencies = [ + "borsh 1.5.5", + "serde", + "serde_derive", + "solana-instruction", + "solana-sdk-ids", ] [[package]] name = "solana-cpi" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00bae0591481827ac9cfce5573aad2918bb01f91289b811ea531df4fcb73d136" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" dependencies = [ "solana-account-info", "solana-define-syscall", @@ -2550,63 +2710,155 @@ dependencies = [ [[package]] name = "solana-curve25519" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ec1e9b0cf73334da62f82ac9c19985f18410c2e59f020c0e4a8cf18d1607ef" +checksum = "28e46b297431ab5a67b99d9aba1e7cff16105e4d44e1c0b92c916935d86b2424" dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", - "solana-program", - "thiserror 1.0.69", + "solana-define-syscall", + "subtle", + "thiserror 2.0.11", ] [[package]] name = "solana-decode-error" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8880dc18fb97c6205214d1f3ce2f1152e997ecc6f6da4bb458fbf6e6207a0693" +checksum = "10a6a6383af236708048f8bd8d03db8ca4ff7baf4a48e5d580f4cce545925470" dependencies = [ "num-traits", ] [[package]] name = "solana-define-syscall" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6452c4a8fc77cc60ad2934b19f2d75691067f17355b34462d52285395c1c99db" +checksum = "cf784bb2cb3e02cac9801813c30187344228d2ae952534902108f6150573a33d" [[package]] name = "solana-derivation-path" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a03d1149b531c0740a96f36445eec5a937f364729515c924808c40c3706b3b55" +checksum = "939756d798b25c5ec3cca10e06212bdca3b1443cb9bb740a38124f58b258737b" dependencies = [ "derivation-path", "qstring", "uriparse", ] +[[package]] +name = "solana-ed25519-program" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0c4dfce08d71d8f1e9b7d1b4e2c7101a8109903ad481acbbc1119a73d459f2" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "ed25519-dalek", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-sdk-ids", +] + +[[package]] +name = "solana-epoch-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ef6f0b449290b0b9f32973eefd95af35b01c5c0c34c569f936c34c5b20d77b" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-epoch-rewards" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-rewards-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c5fd2662ae7574810904585fd443545ed2b568dbd304b25a31e79ccc76e81b" +dependencies = [ + "siphasher", + "solana-hash", + "solana-pubkey", +] + [[package]] name = "solana-epoch-schedule" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e783a735416c534228f24f18f18ade0b189c2c8a93be486c9a26bd314517d93" +checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" dependencies = [ "serde", "serde_derive", + "solana-sdk-ids", "solana-sdk-macro", "solana-sysvar-id", ] +[[package]] +name = "solana-example-mocks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash", + "solana-instruction", + "solana-keccak-hasher", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9c7fbf3e58b64a667c5f35e90af580538a95daea7001ff7806c0662d301bdf" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", +] + [[package]] name = "solana-feature-set" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb12f174930110d90589281795fd17e03389e22170461a4d528212865e13c621" +checksum = "89e1d3b52b4a014efeaaab67f14e40af3972a4be61c523d612860db8e3145529" dependencies = [ + "ahash", "lazy_static", - "solana-clock", "solana-epoch-schedule", "solana-hash", "solana-pubkey", @@ -2615,22 +2867,75 @@ dependencies = [ [[package]] name = "solana-fee-calculator" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fa18582732d94369263c42eeee967ff919e99b9b15ba747fb7534aa24fbbc0" +checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" dependencies = [ "log", "serde", "serde_derive", ] +[[package]] +name = "solana-fee-structure" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f45f94a88efdb512805563181dfa1c85c60a21b6e6d602bf24a2ea88f9399d6e" +dependencies = [ + "serde", + "serde_derive", + "solana-message", + "solana-native-token", +] + +[[package]] +name = "solana-genesis-config" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968dabd2b92d57131473eddbd475339da530e14f54397386abf303de3a2595a2" +dependencies = [ + "bincode", + "chrono", + "memmap2", + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-cluster-type", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-inflation", + "solana-keypair", + "solana-logger", + "solana-native-token", + "solana-poh-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-shred-version", + "solana-signer", + "solana-time-utils", +] + +[[package]] +name = "solana-hard-forks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c28371f878e2ead55611d8ba1b5fb879847156d04edea13693700ad1a28baf" +dependencies = [ + "serde", + "serde_derive", +] + [[package]] name = "solana-hash" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e35f984e3d60a58184743446250cf724afb34ed65f794da0dc4b462f9c1929" +checksum = "cf7bcb14392900fe02e4e34e90234fbf0c673d4e327888410ba99fa2ba0f4e99" dependencies = [ - "borsh 1.5.4", + "borsh 1.5.5", "bs58", "bytemuck", "bytemuck_derive", @@ -2644,9 +2949,9 @@ dependencies = [ [[package]] name = "solana-inflation" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "072f2f3562b4a77a1873250e9e6239389887114ed28846c1174e68979ce021a8" +checksum = "23eef6a09eb8e568ce6839573e4966850e85e9ce71e6ae1a6c930c1c43947de3" dependencies = [ "serde", "serde_derive", @@ -2654,12 +2959,12 @@ dependencies = [ [[package]] name = "solana-instruction" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35fc69f7f75df0b11e99c03393b24a7443aec0430518054de14715c59cfa716d" +checksum = "9ce496a475e5062ba5de97215ab39d9c358f9c9df4bb7f3a45a1f1a8bd9065ed" dependencies = [ "bincode", - "borsh 1.5.4", + "borsh 1.5.5", "getrandom 0.2.15", "js-sys", "num-traits", @@ -2671,31 +2976,124 @@ dependencies = [ ] [[package]] -name = "solana-last-restart-slot" -version = "2.1.8" +name = "solana-instructions-sysvar" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee98cc25000ee8bab1a4f63c7516d9521bc8a9747d8287ebb05e5d9b1d32ee1" +checksum = "427f2d0d6dc0bb49f16cef5e7f975180d2e80aab9bdd3b2af68e2d029ec63f43" dependencies = [ - "serde", - "serde_derive", - "solana-sdk-macro", - "solana-sysvar-id", -] + "bitflags 2.8.0", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" +dependencies = [ + "sha3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-keypair" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dbb7042c2e0c561afa07242b2099d55c57bd1b1da3b6476932197d84e15e3e4" +dependencies = [ + "bs58", + "ed25519-dalek", + "ed25519-dalek-bip32", + "rand 0.7.3", + "solana-derivation-path", + "solana-pubkey", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "wasm-bindgen", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4be76cfa9afd84ca2f35ebc09f0da0f0092935ccdac0595d98447f259538c2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] [[package]] name = "solana-log-collector" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50f7d13f8e5ef4949066d5993a2f4a776a5d713dcd23c3af21c08383f6d3d5" +checksum = "05db948a307b55c553f6b8a23439b4be619a65552ffc4c88caa5d7dd4bd53001" dependencies = [ "log", ] [[package]] name = "solana-logger" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05de5bd31b0123b9c2c8fa106ae11ad6cff45d77be67a9ac5109407322c58cd4" +checksum = "593dbcb81439d37b02757e90bd9ab56364de63f378c55db92a6fbd6a2e47ab36" dependencies = [ "env_logger", "lazy_static", @@ -2704,45 +3102,113 @@ dependencies = [ [[package]] name = "solana-measure" -version = "2.1.8" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504bfa21b291ad23edf2a9499929b653004f8585acbd32ee1ce186403a2d092d" + +[[package]] +name = "solana-message" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ae355064c63c12ffadedc1c44d9410e0fd4f50923f0503a4367c1f64153d2c" +checksum = "268486ba8a294ed22a4d7c1ec05f540c3dbe71cfa7c6c54b6d4d13668d895678" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] [[package]] name = "solana-metrics" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f4af2c5fdda62f1cc6a88a124f5387aa85cb046dd37a992afa85ae05d59d7d" +checksum = "77daa9b73989b40c5e3c6ab9c8b9a9aa6facf209db8743dd37834975355baf53" dependencies = [ "crossbeam-channel", "gethostname", "lazy_static", "log", "reqwest", - "solana-sdk", - "thiserror 1.0.69", + "solana-clock", + "solana-cluster-type", + "solana-sha256-hasher", + "solana-time-utils", + "thiserror 2.0.11", ] [[package]] name = "solana-msg" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac7a109b0c7a0ed26c1fbf3b0fec8809b5d4c74b5d597f0252d45255fd0d309" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" dependencies = [ "solana-define-syscall", ] [[package]] name = "solana-native-token" -version = "2.1.8" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e9de00960197412e4be3902a6cd35e60817c511137aca6c34c66cd5d4017ec" + +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-nonce-account" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7246817ae265f5a67be25f32ee52267f1c2fe29767ab601ef03c5086bfc64992" +checksum = "cde971a20b8dbf60144d6a84439dda86b5466e00e2843091fe731083cda614da" +dependencies = [ + "solana-account", + "solana-hash", + "solana-nonce", + "solana-sdk-ids", +] + +[[package]] +name = "solana-offchain-message" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b526398ade5dea37f1f147ce55dae49aa017a5d7326606359b0445ca8d946581" +dependencies = [ + "num_enum", + "solana-hash", + "solana-packet", + "solana-pubkey", + "solana-sanitize", + "solana-sha256-hasher", + "solana-signature", + "solana-signer", +] [[package]] name = "solana-packet" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4153becc47f7367102710ae3ddbae46b5aa1b004da4cab8101eaf7d6d0b911b0" +checksum = "004f2d2daf407b3ec1a1ca5ec34b3ccdfd6866dd2d3c7d0715004a96e4b6d127" dependencies = [ "bincode", "bitflags 2.8.0", @@ -2752,78 +3218,119 @@ dependencies = [ "serde_with", ] +[[package]] +name = "solana-poh-config" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d650c3b4b9060082ac6b0efbbb66865089c58405bfb45de449f3f2b91eccee75" +dependencies = [ + "serde", + "serde_derive", +] + [[package]] name = "solana-poseidon" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a97dd90dd8cc62edf994c146b352fc430a87d7735bb672d6ed1a14d851cc96" +checksum = "360635ce7e20eec1cf9b400d2d962580bca34562bee8e0a34825f26565a4f5ea" dependencies = [ "ark-bn254", "light-poseidon", "solana-define-syscall", - "thiserror 1.0.69", + "thiserror 2.0.11", ] [[package]] name = "solana-precompile-error" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed911c6c1ec277b55cf5f082a893023a8a7a58b520823d9ef65f36ace939f2b" +checksum = "4ff64daa2933c22982b323d88d0cdf693201ef56ac381ae16737fd5f579e07d6" dependencies = [ "num-traits", "solana-decode-error", ] +[[package]] +name = "solana-precompiles" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a460ab805ec063802105b463ecb5eb02c3ffe469e67a967eea8a6e778e0bc06" +dependencies = [ + "lazy_static", + "solana-ed25519-program", + "solana-feature-set", + "solana-message", + "solana-precompile-error", + "solana-pubkey", + "solana-sdk-ids", + "solana-secp256k1-program", + "solana-secp256r1-program", +] + +[[package]] +name = "solana-presigner" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a57a24e6a4125fc69510b6774cd93402b943191b6cddad05de7281491c90fe" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-signer", +] + [[package]] name = "solana-program" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb05f5ffadb039285ee82efd9a593e0873220f840f0eac7069d962f9eb29a407" +checksum = "586469467e93ceb79048f8d8e3a619bf61d05396ee7de95cb40280301a589d05" dependencies = [ - "base64 0.22.1", "bincode", - "bitflags 2.8.0", "blake3", "borsh 0.10.4", - "borsh 1.5.4", + "borsh 1.5.5", "bs58", - "bv", "bytemuck", - "bytemuck_derive", "console_error_panic_hook", "console_log", - "curve25519-dalek 4.1.3", - "five8_const", "getrandom 0.2.15", - "js-sys", "lazy_static", "log", "memoffset", "num-bigint 0.4.6", "num-derive", "num-traits", - "parking_lot", "rand 0.8.5", "serde", "serde_bytes", "serde_derive", - "sha2 0.10.8", - "sha3", "solana-account-info", + "solana-address-lookup-table-interface", "solana-atomic-u64", + "solana-big-mod-exp", "solana-bincode", + "solana-blake3-hasher", "solana-borsh", "solana-clock", "solana-cpi", "solana-decode-error", "solana-define-syscall", + "solana-epoch-rewards", "solana-epoch-schedule", + "solana-example-mocks", + "solana-feature-gate-interface", "solana-fee-calculator", "solana-hash", "solana-instruction", + "solana-instructions-sysvar", + "solana-keccak-hasher", "solana-last-restart-slot", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-message", "solana-msg", "solana-native-token", + "solana-nonce", "solana-program-entrypoint", "solana-program-error", "solana-program-memory", @@ -2832,6 +3339,7 @@ dependencies = [ "solana-pubkey", "solana-rent", "solana-sanitize", + "solana-sdk-ids", "solana-sdk-macro", "solana-secp256k1-recover", "solana-serde-varint", @@ -2841,17 +3349,20 @@ dependencies = [ "solana-slot-hashes", "solana-slot-history", "solana-stable-layout", + "solana-stake-interface", + "solana-system-interface", + "solana-sysvar", "solana-sysvar-id", - "solana-transaction-error", - "thiserror 1.0.69", + "solana-vote-interface", + "thiserror 2.0.11", "wasm-bindgen", ] [[package]] name = "solana-program-entrypoint" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f6148e740c6deed55fe343355f0cb3ec158d221e11aa8bb93a392fa62c4137" +checksum = "473ffe73c68d93e9f2aa726ad2985fe52760052709aaab188100a42c618060ec" dependencies = [ "solana-account-info", "solana-msg", @@ -2861,11 +3372,11 @@ dependencies = [ [[package]] name = "solana-program-error" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87e99e4299728f450194b6adf946dde512d79d82275b1c73f6faea7e9075cef" +checksum = "d8ae2c1a8d0d4ae865882d5770a7ebca92bab9c685e43f0461682c6c05a35bfa" dependencies = [ - "borsh 1.5.4", + "borsh 1.5.5", "num-traits", "serde", "serde_derive", @@ -2877,9 +3388,9 @@ dependencies = [ [[package]] name = "solana-program-memory" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3691cdd84c0a4753b484f468aac19e0943fab1e71705b21d00d561ac6eea6449" +checksum = "1b0268f6c89825fb634a34bd0c3b8fdaeaecfc3728be1d622a8ee6dd577b60d4" dependencies = [ "num-traits", "solana-define-syscall", @@ -2887,57 +3398,68 @@ dependencies = [ [[package]] name = "solana-program-option" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e99a3e016363a95cdbe23aaa2a68578ffa2ce8e37c4a642962201af6376ffc37" +checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" [[package]] name = "solana-program-pack" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eba980dec9d5403ea299a3cdf27cd794e6b1a188acc8c5e3ae7d067b629eb24" +checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" dependencies = [ "solana-program-error", ] [[package]] name = "solana-program-runtime" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "554db6e468732aa8b0a06a6d4f7b9aa87c9af3e230cec0de3d114d05ae562516" +checksum = "ef8ce68ce0f2777490a7ca3662d1c793e1dd5a400c9772514025185838fc5162" dependencies = [ "base64 0.22.1", "bincode", "enum-iterator", "itertools 0.12.1", - "libc", "log", - "num-derive", - "num-traits", "percentage", "rand 0.8.5", "serde", + "solana-account", + "solana-clock", "solana-compute-budget", + "solana-epoch-rewards", + "solana-epoch-schedule", "solana-feature-set", + "solana-hash", + "solana-instruction", + "solana-last-restart-slot", "solana-log-collector", "solana-measure", "solana-metrics", - "solana-sdk", + "solana-precompiles", + "solana-pubkey", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-stable-layout", + "solana-sysvar", + "solana-sysvar-id", "solana-timings", + "solana-transaction-context", "solana-type-overrides", - "solana-vote", - "solana_rbpf", - "thiserror 1.0.69", + "thiserror 2.0.11", ] [[package]] name = "solana-pubkey" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dba2b19db8b73ab96b309b6d2a9f26386e45e2af3618a27b92389da9a3df1f1" +checksum = "40db1ff5a0f8aea2c158d78ab5f2cf897848964251d1df42fef78efd3c85b863" dependencies = [ "borsh 0.10.4", - "borsh 1.5.4", + "borsh 1.5.5", "bs58", "bytemuck", "bytemuck_derive", @@ -2957,93 +3479,185 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "solana-quic-definitions" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e606feac5110eb5d8afaa43ccaeea3ec49ccec36773387930b5ba545e745aea2" +dependencies = [ + "solana-keypair", +] + [[package]] name = "solana-rent" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138b60a6683d14d63b4cee532d50afcb54999679b5c53013969fd51977455e14" +checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" dependencies = [ "serde", "serde_derive", + "solana-sdk-ids", "solana-sdk-macro", "solana-sysvar-id", ] +[[package]] +name = "solana-rent-collector" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c1e19f5d5108b0d824244425e43bc78bbb9476e2199e979b0230c9f632d3bf4" +dependencies = [ + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-epoch-schedule", + "solana-genesis-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", +] + +[[package]] +name = "solana-rent-debits" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f6f9113c6003492e74438d1288e30cffa8ccfdc2ef7b49b9e816d8034da18cd" +dependencies = [ + "solana-pubkey", + "solana-reward-info", +] + +[[package]] +name = "solana-reserved-account-keys" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b293f4246626c0e0a991531f08848a713ada965612e99dc510963f04d12cae7" +dependencies = [ + "lazy_static", + "solana-feature-set", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-reward-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18205b69139b1ae0ab8f6e11cdcb627328c0814422ad2482000fa2ca54ae4a2f" +dependencies = [ + "serde", + "serde_derive", +] + [[package]] name = "solana-sanitize" -version = "2.1.8" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" + +[[package]] +name = "solana-sbpf" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f71b885b953e9157b66eaba9a34507f2f840712ef54f483725ba510ee1bd89" +checksum = "66a3ce7a0f4d6830124ceb2c263c36d1ee39444ec70146eb49b939e557e72b96" +dependencies = [ + "byteorder", + "combine", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "thiserror 1.0.69", + "winapi", +] [[package]] name = "solana-sdk" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a9bcaaedaf805d5541307e22b48ba80a5b0e2922c2d35ca7f23732efa6bd07" +checksum = "4808e8d7f3c931657e615042d4176b423e66f64dc99e3dc3c735a197e512029b" dependencies = [ "bincode", - "bitflags 2.8.0", - "borsh 1.5.4", "bs58", - "bytemuck", - "bytemuck_derive", - "byteorder", - "chrono", - "digest 0.10.7", - "ed25519-dalek", - "ed25519-dalek-bip32", "getrandom 0.1.16", - "hmac 0.12.1", - "itertools 0.12.1", "js-sys", - "lazy_static", - "libsecp256k1", - "log", - "memmap2", - "num-derive", - "num-traits", - "num_enum", - "pbkdf2", - "rand 0.7.3", - "rand 0.8.5", "serde", - "serde_bytes", - "serde_derive", "serde_json", - "serde_with", - "sha2 0.10.8", - "sha3", - "siphasher", "solana-account", "solana-bn254", + "solana-client-traits", + "solana-cluster-type", + "solana-commitment-config", + "solana-compute-budget-interface", "solana-decode-error", "solana-derivation-path", + "solana-ed25519-program", + "solana-epoch-info", + "solana-epoch-rewards-hasher", "solana-feature-set", + "solana-fee-structure", + "solana-genesis-config", + "solana-hard-forks", "solana-inflation", "solana-instruction", + "solana-keypair", + "solana-message", "solana-native-token", + "solana-nonce-account", + "solana-offchain-message", "solana-packet", + "solana-poh-config", "solana-precompile-error", + "solana-precompiles", + "solana-presigner", "solana-program", "solana-program-memory", "solana-pubkey", + "solana-quic-definitions", + "solana-rent-collector", + "solana-rent-debits", + "solana-reserved-account-keys", + "solana-reward-info", "solana-sanitize", + "solana-sdk-ids", "solana-sdk-macro", + "solana-secp256k1-program", "solana-secp256k1-recover", "solana-secp256r1-program", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-serde", "solana-serde-varint", "solana-short-vec", + "solana-shred-version", "solana-signature", + "solana-signer", + "solana-system-transaction", + "solana-time-utils", + "solana-transaction", + "solana-transaction-context", "solana-transaction-error", - "thiserror 1.0.69", + "solana-validator-exit", + "thiserror 2.0.11", "wasm-bindgen", ] +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey", +] + [[package]] name = "solana-sdk-macro" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f0b358f336ceac3827881915e5293f121c023cbd2150115046356c66898cb8" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" dependencies = [ "bs58", "proc-macro2", @@ -3051,46 +3665,93 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "solana-secp256k1-program" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a1caa972414cc78122c32bdae65ac5fe89df7db598585a5cde19d16a20280a" +dependencies = [ + "bincode", + "digest 0.10.7", + "libsecp256k1", + "serde", + "serde_derive", + "sha3", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-sdk-ids", +] + [[package]] name = "solana-secp256k1-recover" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460c2e36586bcce843cdeaaf2364f3db7fbd9f266325e93d5e9af33f2605dd7d" +checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" dependencies = [ - "borsh 1.5.4", + "borsh 1.5.5", "libsecp256k1", "solana-define-syscall", - "thiserror 1.0.69", + "thiserror 2.0.11", ] [[package]] name = "solana-secp256r1-program" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993ec6151c8f8ce77378a2506831c869b27ebdb0eaf65b375d38a4798c20d56" +checksum = "c9ea9282950921611bd9e0200da7236fbb1d4f8388942f8451bd55e9f3cb228f" dependencies = [ "bytemuck", "openssl", "solana-feature-set", "solana-instruction", "solana-precompile-error", - "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-seed-derivable" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beb82b5adb266c6ea90e5cf3967235644848eac476c5a1f2f9283a143b7c97f" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "sha2 0.10.8", +] + +[[package]] +name = "solana-serde" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1931484a408af466e14171556a47adaa215953c7f48b24e5f6b0282763818b04" +dependencies = [ + "serde", ] [[package]] name = "solana-serde-varint" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98449030e53dcc2c4f160acab99b2bdb3e24ea8bff8ca6e71a6e539a54bf3d7" +checksum = "bcc07d00200d82e6def2f7f7a45738e3406b17fe54a18adcf0defa16a97ccadb" dependencies = [ "serde", ] [[package]] name = "solana-serialize-utils" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d659aac218580fc3fb3e8350669db9bb01bc1bc849c90f0741cbfccb6663eb94" +checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" dependencies = [ "solana-instruction", "solana-pubkey", @@ -3099,9 +3760,9 @@ dependencies = [ [[package]] name = "solana-sha256-hasher" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0db90ad6643d4d626f923159eaa876000c09f8c2e9aa7ff59b803e8328712582" +checksum = "0037386961c0d633421f53560ad7c80675c0447cba4d1bb66d60974dd486c7ea" dependencies = [ "sha2 0.10.8", "solana-define-syscall", @@ -3110,157 +3771,323 @@ dependencies = [ [[package]] name = "solana-short-vec" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f7de721a6c50cb3a41e027a623496be39e45c452fbf897f657cd1f2f67dbbd" +checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" dependencies = [ "serde", ] +[[package]] +name = "solana-shred-version" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afd3db0461089d1ad1a78d9ba3f15b563899ca2386351d38428faa5350c60a98" +dependencies = [ + "solana-hard-forks", + "solana-hash", + "solana-sha256-hasher", +] + [[package]] name = "solana-signature" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3123b0fba3a798cbb2091788c92880644464e56359abc7defed993c6efa88ef3" +checksum = "47d251c8f3dc015f320b4161daac7f108156c837428e5a8cc61136d25beb11d6" dependencies = [ "bs58", "ed25519-dalek", - "generic-array", "rand 0.8.5", "serde", + "serde-big-array", "serde_derive", "solana-sanitize", ] +[[package]] +name = "solana-signer" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-transaction-error", +] + [[package]] name = "solana-slot-hashes" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3840867aa6d0fac65d3a4c1f14fff650a8e148732a16c06ebd8a2389d79d4745" +checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" dependencies = [ "serde", "serde_derive", "solana-hash", + "solana-sdk-ids", "solana-sysvar-id", ] [[package]] name = "solana-slot-history" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "101583a12fcce9b52f845b3c773f4ae6c3f4ca6a46177dadbd83e276baf82326" +checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" dependencies = [ "bv", "serde", "serde_derive", + "solana-sdk-ids", "solana-sysvar-id", ] [[package]] name = "solana-stable-layout" -version = "2.1.8" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.5", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-system-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-system-interface" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b923e1c9e42b6c98b1786ca003af6a0366932f08d63432e984fcc394b7b5e" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" dependencies = [ + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", "solana-instruction", "solana-pubkey", + "wasm-bindgen", ] [[package]] name = "solana-system-program" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f37c7ac5c53f2a0c5222f24146ad8bf7ce84e96551997c05984264d5bdae1a9" +checksum = "ef4c7851977d6fc24c5d734b836c5c1d5c0f40d07d835c1bcc76021e325492c5" dependencies = [ "bincode", "log", "serde", "serde_derive", + "solana-account", + "solana-bincode", + "solana-instruction", "solana-log-collector", + "solana-nonce", + "solana-nonce-account", + "solana-packet", "solana-program-runtime", - "solana-sdk", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", + "solana-sysvar", + "solana-transaction-context", "solana-type-overrides", ] +[[package]] +name = "solana-system-transaction" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd98a25e5bcba8b6be8bcbb7b84b24c2a6a8178d7fb0e3077a916855ceba91a" +dependencies = [ + "solana-hash", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-signer", + "solana-system-interface", + "solana-transaction", +] + +[[package]] +name = "solana-sysvar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6b44740d7f0c9f375d045c165bc0aab4a90658f92d6835aeb0649afaeaff9a" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-sysvar-id", +] + [[package]] name = "solana-sysvar-id" -version = "2.1.8" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59351de877a7cf0cea0e436424ecf4ea0c08c59ff01ef0575436972b920b818c" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" dependencies = [ "solana-pubkey", + "solana-sdk-ids", ] +[[package]] +name = "solana-time-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af261afb0e8c39252a04d026e3ea9c405342b08c871a2ad8aa5448e068c784c" + [[package]] name = "solana-timings" -version = "2.1.8" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bca35719b09d4d9abac84fce42a448d86eb62edc69404ce85077874469e46" +checksum = "6f59d5f154e1b2fb4aef3257af4b4823e2c2e61c3d77e52e5ef28464d37453c4" dependencies = [ "eager", "enum-iterator", - "solana-sdk", + "solana-pubkey", ] [[package]] -name = "solana-transaction-error" -version = "2.1.8" +name = "solana-transaction" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3d2147cfaad2a5518b8e15621008699e28d32d6233cd7a6b27a506e01f1515" +checksum = "753b3e9afed170e4cfc0ea1e87b5dfdc6d4a50270869414edd24c6ea1f529b29" dependencies = [ + "bincode", "serde", "serde_derive", + "solana-bincode", + "solana-feature-set", + "solana-hash", "solana-instruction", + "solana-keypair", + "solana-message", + "solana-precompiles", + "solana-pubkey", + "solana-reserved-account-keys", "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", ] [[package]] -name = "solana-type-overrides" -version = "2.1.8" +name = "solana-transaction-context" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3cac7e7628c46bf5e243a4b0f11c0ad172a27cae2a5d97c7c6ca64fe9e6ece6" +checksum = "5022de04cbba05377f68bf848c8c1322ead733f88a657bf792bb40f3257b8218" dependencies = [ - "lazy_static", - "rand 0.8.5", + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-signature", ] [[package]] -name = "solana-vote" -version = "2.1.8" +name = "solana-transaction-error" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490e9e84d72423b90f1adcc232051a4e3719bf3498508ea9ba9d15e967f4d327" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" dependencies = [ - "itertools 0.12.1", - "log", "serde", "serde_derive", - "solana-sdk", - "thiserror 1.0.69", + "solana-instruction", + "solana-sanitize", ] [[package]] -name = "solana_rbpf" -version = "0.8.5" +name = "solana-type-overrides" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1941b5ef0c3ce8f2ac5dd984d0fb1a97423c4ff2a02eec81e3913f02e2ac2b" +checksum = "040beb66259d485dd8623cddb8f5e8d537a8e3e0d893b84b0239423b1a6460ce" dependencies = [ - "byteorder", - "combine", - "hash32", - "libc", - "log", + "lazy_static", "rand 0.8.5", - "rustc-demangle", - "scroll", - "thiserror 1.0.69", - "winapi", ] [[package]] -name = "spin" -version = "0.9.8" +name = "solana-validator-exit" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "7bbf6d7a3c0b28dd5335c52c0e9eae49d0ae489a8f324917faf0ded65a812c1d" + +[[package]] +name = "solana-vote-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e9f6a1651310a94cd5a1a6b7f33ade01d9e5ea38a2220becb5fd737b756514" +dependencies = [ + "bincode", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-decode-error", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface", +] [[package]] name = "spl-token" @@ -3275,8 +4102,23 @@ dependencies = [ "num_enum", "proptest", "serial_test", - "solana-program", + "solana-account-info", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-native-token", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", "solana-sdk", + "solana-sdk-ids", + "solana-sysvar", "thiserror 2.0.11", ] diff --git a/program/Cargo.toml b/program/Cargo.toml index 66123c2..8971f63 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -17,15 +17,30 @@ bytemuck = "1.20.0" num-derive = "0.4" num-traits = "0.2" num_enum = "0.7.3" -solana-program = "2.1.0" +solana-account-info = "2.2.0" +solana-cpi = "2.2.0" +solana-decode-error = "2.2.0" +solana-instruction = "2.2.0" +solana-msg = "2.2.0" +solana-program-entrypoint = "2.2.0" +solana-program-error = "2.2.0" +solana-program-memory = "2.2.0" +solana-program-option = "2.2.0" +solana-program-pack = "2.2.0" +solana-pubkey = { version = "2.2.0", features = ["bytemuck"] } +solana-rent = "2.2.0" +solana-sdk-ids = "2.2.0" +solana-sysvar = { version = "2.2.0", features = ["bincode"] } thiserror = "2.0" [dev-dependencies] lazy_static = "1.5.0" -mollusk-svm = { version = "0.0.13", git = "https://github.com/buffalojoec/mollusk.git" } +mollusk-svm = "0.1.0" proptest = "1.5" serial_test = "3.2.0" -solana-sdk = "2.1.0" +solana-clock = "2.2.1" +solana-native-token = "2.2.1" +solana-sdk = "2.2.1" [lib] crate-type = ["cdylib", "lib"] diff --git a/program/src/entrypoint.rs b/program/src/entrypoint.rs index 366ee78..ad18ed4 100644 --- a/program/src/entrypoint.rs +++ b/program/src/entrypoint.rs @@ -2,13 +2,12 @@ use { crate::{error::TokenError, processor::Processor}, - solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::PrintProgramError, - pubkey::Pubkey, - }, + solana_account_info::AccountInfo, + solana_program_error::{PrintProgramError, ProgramResult}, + solana_pubkey::Pubkey, }; -solana_program::entrypoint!(process_instruction); +solana_program_entrypoint::entrypoint!(process_instruction); fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], diff --git a/program/src/error.rs b/program/src/error.rs index a758d2c..d371cf9 100644 --- a/program/src/error.rs +++ b/program/src/error.rs @@ -2,11 +2,9 @@ use { num_derive::FromPrimitive, - solana_program::{ - decode_error::DecodeError, - msg, - program_error::{PrintProgramError, ProgramError}, - }, + solana_decode_error::DecodeError, + solana_msg::msg, + solana_program_error::{PrintProgramError, ProgramError}, thiserror::Error, }; diff --git a/program/src/instruction.rs b/program/src/instruction.rs index b797a7d..b0c0c64 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -2,13 +2,11 @@ use { crate::{check_program_account, error::TokenError}, - solana_program::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_option::COption, - pubkey::Pubkey, - sysvar, - }, + solana_instruction::{AccountMeta, Instruction}, + solana_program_error::ProgramError, + solana_program_option::COption, + solana_pubkey::Pubkey, + solana_sdk_ids::sysvar, std::{convert::TryInto, mem::size_of}, }; diff --git a/program/src/lib.rs b/program/src/lib.rs index 25175df..2690a46 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -13,10 +13,33 @@ pub mod state; #[cfg(not(feature = "no-entrypoint"))] mod entrypoint; -// Export current sdk types for downstream users building with a different sdk -// version -pub use solana_program; -use solana_program::{entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey}; +/// Export current sdk types for downstream users building with a different sdk +/// version +pub mod solana_program { + #![allow(missing_docs)] + pub mod entrypoint { + pub use solana_program_error::ProgramResult; + } + pub mod instruction { + pub use solana_instruction::{AccountMeta, Instruction}; + } + pub mod program_error { + pub use solana_program_error::{PrintProgramError, ProgramError}; + } + pub mod program_option { + pub use solana_program_option::COption; + } + pub mod program_pack { + pub use solana_program_pack::{IsInitialized, Pack, Sealed}; + } + pub mod pubkey { + pub use solana_pubkey::{Pubkey, PUBKEY_BYTES}; + } +} +use { + solana_program_error::{ProgramError, ProgramResult}, + solana_pubkey::Pubkey, +}; /// Convert the UI representation of a token amount (using the decimals field /// defined in its mint) to the raw amount @@ -82,7 +105,7 @@ pub fn try_ui_amount_into_amount(ui_amount: String, decimals: u8) -> Result ProgramResult { diff --git a/program/src/native_mint.rs b/program/src/native_mint.rs index bd489ee..ef0eb57 100644 --- a/program/src/native_mint.rs +++ b/program/src/native_mint.rs @@ -4,11 +4,11 @@ pub const DECIMALS: u8 = 9; // The Mint for native SOL Token accounts -solana_program::declare_id!("So11111111111111111111111111111111111111112"); +solana_pubkey::declare_id!("So11111111111111111111111111111111111111112"); #[cfg(test)] mod tests { - use {super::*, solana_program::native_token::*}; + use {super::*, solana_native_token::*}; #[test] fn test_decimals() { diff --git a/program/src/processor.rs b/program/src/processor.rs index 56e9e4a..555ceec 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -8,19 +8,17 @@ use { state::{Account, AccountState, Mint, Multisig}, try_ui_amount_into_amount, }, - solana_program::{ - account_info::{next_account_info, AccountInfo}, - entrypoint::ProgramResult, - msg, - program::set_return_data, - program_error::ProgramError, - program_memory::sol_memcmp, - program_option::COption, - program_pack::{IsInitialized, Pack}, - pubkey::{Pubkey, PUBKEY_BYTES}, - system_program, - sysvar::{rent::Rent, Sysvar}, - }, + solana_account_info::{next_account_info, AccountInfo}, + solana_cpi::set_return_data, + solana_msg::msg, + solana_program_error::{ProgramError, ProgramResult}, + solana_program_memory::sol_memcmp, + solana_program_option::COption, + solana_program_pack::{IsInitialized, Pack}, + solana_pubkey::{Pubkey, PUBKEY_BYTES}, + solana_rent::Rent, + solana_sdk_ids::system_program, + solana_sysvar::Sysvar, }; /// Program state handler. @@ -695,7 +693,7 @@ impl Processor { authority_info, account_info_iter.as_slice(), )?; - } else if !solana_program::incinerator::check_id(destination_account_info.key) { + } else if !solana_sdk_ids::incinerator::check_id(destination_account_info.key) { return Err(ProgramError::InvalidAccountData); } @@ -1027,7 +1025,7 @@ fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { account_info.assign(&system_program::id()); let mut account_data = account_info.data.borrow_mut(); let data_len = account_data.len(); - solana_program::program_memory::sol_memset(*account_data, 0, data_len); + solana_program_memory::sol_memset(*account_data, 0, data_len); Ok(()) } @@ -1042,7 +1040,8 @@ fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> { mod tests { use { super::*, - solana_program::{clock::Epoch, program_error::PrintProgramError}, + solana_clock::Epoch, + solana_program_error::PrintProgramError, std::sync::{Arc, RwLock}, }; diff --git a/program/src/state.rs b/program/src/state.rs index f7595e7..1bf00f7 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -4,12 +4,10 @@ use { crate::instruction::MAX_SIGNERS, arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}, num_enum::TryFromPrimitive, - solana_program::{ - program_error::ProgramError, - program_option::COption, - program_pack::{IsInitialized, Pack, Sealed}, - pubkey::{Pubkey, PUBKEY_BYTES}, - }, + solana_program_error::ProgramError, + solana_program_option::COption, + solana_program_pack::{IsInitialized, Pack, Sealed}, + solana_pubkey::{Pubkey, PUBKEY_BYTES}, }; /// Mint data. @@ -120,8 +118,8 @@ impl Account { /// Checks if a token Account's owner is the `system_program` or the /// incinerator pub fn is_owned_by_system_program_or_incinerator(&self) -> bool { - solana_program::system_program::check_id(&self.owner) - || solana_program::incinerator::check_id(&self.owner) + solana_sdk_ids::system_program::check_id(&self.owner) + || solana_sdk_ids::incinerator::check_id(&self.owner) } } impl Sealed for Account {} diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 1fd1edc..3e8ad71 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -3833,7 +3833,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &program_id, &incinerator_account_key, &mint_key, - &solana_program::incinerator::id(), + &solana_sdk_ids::incinerator::id(), ) .unwrap(), vec![&mut incinerator_account, &mut mint_account], @@ -3845,7 +3845,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { &program_id, &system_account_key, &mint_key, - &solana_program::system_program::id(), + &solana_sdk_ids::system_program::id(), ) .unwrap(), vec![&mut system_account, &mut mint_account], @@ -3906,7 +3906,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { close_account( &program_id, &incinerator_account_key, - &solana_program::incinerator::id(), + &solana_sdk_ids::incinerator::id(), &owner_key, &[] ) @@ -3925,7 +3925,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { close_account( &program_id, &system_account_key, - &solana_program::incinerator::id(), + &solana_sdk_ids::incinerator::id(), &owner_key, &[] ) @@ -4022,7 +4022,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { close_account( &program_id, &incinerator_account_key, - &solana_program::incinerator::id(), + &solana_sdk_ids::incinerator::id(), &owner_key, &[], ) @@ -4040,7 +4040,7 @@ fn test_burn_and_close_system_and_incinerator_tokens() { close_account( &program_id, &system_account_key, - &solana_program::incinerator::id(), + &solana_sdk_ids::incinerator::id(), &owner_key, &[], ) diff --git a/scripts/solana.dic b/scripts/solana.dic index 2530ee1..62a3ad8 100644 --- a/scripts/solana.dic +++ b/scripts/solana.dic @@ -49,3 +49,4 @@ staker/S APY codama autogenerated +sdk From 06677863f65fc307967df6ae3c1f48e1d8654a09 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Mon, 3 Mar 2025 15:30:18 +0000 Subject: [PATCH 307/335] Bump Codama to 1.2.8 and use @solana/kit (#29) --- clients/js/package.json | 4 +- clients/js/pnpm-lock.yaml | 571 +++++++++++++++++- clients/js/src/generated/accounts/mint.ts | 2 +- clients/js/src/generated/accounts/multisig.ts | 2 +- clients/js/src/generated/accounts/token.ts | 2 +- .../src/generated/errors/associatedToken.ts | 2 +- clients/js/src/generated/errors/token.ts | 2 +- .../instructions/amountToUiAmount.ts | 2 +- .../js/src/generated/instructions/approve.ts | 2 +- .../generated/instructions/approveChecked.ts | 2 +- clients/js/src/generated/instructions/burn.ts | 2 +- .../src/generated/instructions/burnChecked.ts | 2 +- .../generated/instructions/closeAccount.ts | 2 +- .../instructions/createAssociatedToken.ts | 2 +- .../createAssociatedTokenIdempotent.ts | 2 +- .../generated/instructions/freezeAccount.ts | 2 +- .../instructions/getAccountDataSize.ts | 2 +- .../instructions/initializeAccount.ts | 2 +- .../instructions/initializeAccount2.ts | 2 +- .../instructions/initializeAccount3.ts | 2 +- .../instructions/initializeImmutableOwner.ts | 2 +- .../generated/instructions/initializeMint.ts | 2 +- .../generated/instructions/initializeMint2.ts | 2 +- .../instructions/initializeMultisig.ts | 2 +- .../instructions/initializeMultisig2.ts | 2 +- .../js/src/generated/instructions/mintTo.ts | 2 +- .../generated/instructions/mintToChecked.ts | 2 +- .../recoverNestedAssociatedToken.ts | 2 +- .../js/src/generated/instructions/revoke.ts | 2 +- .../generated/instructions/setAuthority.ts | 2 +- .../src/generated/instructions/syncNative.ts | 2 +- .../src/generated/instructions/thawAccount.ts | 2 +- .../js/src/generated/instructions/transfer.ts | 2 +- .../generated/instructions/transferChecked.ts | 2 +- .../instructions/uiAmountToAmount.ts | 2 +- .../js/src/generated/pdas/associatedToken.ts | 2 +- .../src/generated/programs/associatedToken.ts | 2 +- clients/js/src/generated/programs/token.ts | 2 +- clients/js/src/generated/shared/index.ts | 6 +- .../js/src/generated/types/accountState.ts | 2 +- .../js/src/generated/types/authorityType.ts | 2 +- clients/js/test/_setup.ts | 2 +- clients/js/test/createAssociatedToken.test.ts | 2 +- .../createAssociatedTokenIdempotent.test.ts | 2 +- clients/js/test/initializeAccount.test.ts | 2 +- clients/js/test/initializeMint.test.ts | 2 +- clients/js/test/mintTo.test.ts | 2 +- clients/js/test/transfer.test.ts | 2 +- package.json | 6 +- pnpm-lock.yaml | 503 +++++++++++---- 50 files changed, 1016 insertions(+), 164 deletions(-) diff --git a/clients/js/package.json b/clients/js/package.json index 1339b8a..854386a 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -42,13 +42,13 @@ }, "homepage": "https://github.com/solana-program/token#readme", "peerDependencies": { - "@solana/web3.js": "^2.0.0" + "@solana/kit": "^2.1.0" }, "devDependencies": { "@ava/typescript": "^4.1.0", "@solana-program/system": "^0.6.1", "@solana/eslint-config-solana": "^3.0.3", - "@solana/web3.js": "^2.0.0", + "@solana/kit": "^2.1.0", "@types/node": "^20", "@typescript-eslint/eslint-plugin": "^7.16.1", "@typescript-eslint/parser": "^7.16.1", diff --git a/clients/js/pnpm-lock.yaml b/clients/js/pnpm-lock.yaml index 3207ce9..2a19da8 100644 --- a/clients/js/pnpm-lock.yaml +++ b/clients/js/pnpm-lock.yaml @@ -17,9 +17,9 @@ importers: '@solana/eslint-config-solana': specifier: ^3.0.3 version: 3.0.3(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-simple-import-sort@10.0.0(eslint@8.57.0))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.2.0(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) - '@solana/web3.js': - specifier: ^2.0.0 - version: 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/kit': + specifier: ^2.1.0 + version: 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) '@types/node': specifier: ^20 version: 20.14.11 @@ -371,36 +371,72 @@ packages: peerDependencies: typescript: '>=5' + '@solana/accounts@2.1.0': + resolution: {integrity: sha512-1JOBiLFeIeHmGx7k1b23UWF9vM1HAh9GBMCzr5rBPrGSBs+QUgxBJ3+yrRg+UPEOSELubqo7qoOVFUKYsb1nXw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/addresses@2.0.0': resolution: {integrity: sha512-8n3c/mUlH1/z+pM8e7OJ6uDSXw26Be0dgYiokiqblO66DGQ0d+7pqFUFZ5pEGjJ9PU2lDTSfY8rHf4cemOqwzQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/addresses@2.1.0': + resolution: {integrity: sha512-IgiRuju2yLz14GnrysOPSNZbZQ8F+7jhx7FYZLrbKogf6NX4wy4ijLHxRsLFqP8o8aY69BZULkM9MwrSjsZi7A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/assertions@2.0.0': resolution: {integrity: sha512-NyPPqZRNGXs/GAjfgsw7YS6vCTXWt4ibXveS+ciy5sdmp/0v3pA6DlzYjleF9Sljrew0IiON15rjaXamhDxYfQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/assertions@2.1.0': + resolution: {integrity: sha512-KCYmxFRsg897Ec7yGdpc0rniOlqGD3NpicmIjWIV87uiXX5uFco4t+01sKyFlhsv4T4OgHxngMsxkfQ3AUkFVg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/codecs-core@2.0.0': resolution: {integrity: sha512-qCG+3hDU5Pm8V6joJjR4j4Zv9md1z0RaecniNDIkEglnxmOUODnmPLWbtOjnDylfItyuZeDihK8hkewdj8cUtw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/codecs-core@2.1.0': + resolution: {integrity: sha512-SR7pKtmJBg2mhmkel2NeHA1pz06QeQXdMv8WJoIR9m8F/hw80K/612uaYbwTt2nkK0jg/Qn/rNSd7EcJ4SBGjw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/codecs-data-structures@2.0.0': resolution: {integrity: sha512-N98Y4jsrC/XeOgqrfsGqcOFIaOoMsKdAxOmy5oqVaEN67YoGSLNC9ROnqamOAOrsZdicTWx9/YLKFmQi9DPh1A==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/codecs-data-structures@2.1.0': + resolution: {integrity: sha512-oDF5ek54kirqJ09q8k/qEpobBiWOhd3CkkGOTyfjsmTF/IGIigNbdYIakxV3+vudBeaNBw08y0XdBYI4JL/nqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/codecs-numbers@2.0.0': resolution: {integrity: sha512-r66i7VzJO1MZkQWZIAI6jjJOFVpnq0+FIabo2Z2ZDtrArFus/SbSEv543yCLeD2tdR/G/p+1+P5On10qF50Y1Q==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/codecs-numbers@2.1.0': + resolution: {integrity: sha512-XMu4yw5iCgQnMKsxSWPPOrGgtaohmupN3eyAtYv3K3C/MJEc5V90h74k5B1GUCiHvcrdUDO9RclNjD9lgbjFag==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/codecs-strings@2.0.0': resolution: {integrity: sha512-dNqeCypsvaHcjW86H0gYgAZGGkKVBeKVeh7WXlOZ9kno7PeQ2wNkpccyzDfuzaIsKv+HZUD3v/eo86GCvnKazQ==} engines: {node: '>=20.18.0'} @@ -408,12 +444,25 @@ packages: fastestsmallesttextencoderdecoder: ^1.0.22 typescript: '>=5' + '@solana/codecs-strings@2.1.0': + resolution: {integrity: sha512-O/eJFLzFrHomcCR1Y5QbIqoPo7iaJaWNnIeskB4mVhVjLyjlJS4WtBP2NBRzM9uJXaXyOxxKroqqO9zFsHOpvQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5' + '@solana/codecs@2.0.0': resolution: {integrity: sha512-xneIG5ppE6WIGaZCK7JTys0uLhzlnEJUdBO8nRVIyerwH6aqCfb0fGe7q5WNNYAVDRSxC0Pc1TDe1hpdx3KWmQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/codecs@2.1.0': + resolution: {integrity: sha512-C0TnfrpbTg7zoIFYfM65ofeL2AWEz80OsD6mjVdcTKpb1Uj7XuBuNLss3dMnatPQaL7RagD9VLA5/WfYayyteQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/errors@2.0.0': resolution: {integrity: sha512-IHlaPFSy4lvYco1oHJ3X8DbchWwAwJaL/4wZKnF1ugwZ0g0re8wbABrqNOe/jyZ84VU9Z14PYM8W9oDAebdJbw==} engines: {node: '>=20.18.0'} @@ -421,6 +470,13 @@ packages: peerDependencies: typescript: '>=5' + '@solana/errors@2.1.0': + resolution: {integrity: sha512-l+GxAv0Ar4d3c3PlZdA9G++wFYZREEbbRyAFP8+n8HSg0vudCuzogh/13io6hYuUhG/9Ve8ARZNamhV7UScKNw==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5' + '@solana/eslint-config-solana@3.0.3': resolution: {integrity: sha512-yTaeCbOBwjmK4oUkknixOpwOzzAK8+4YWvJEJFNHuueESetieDnAeEHV7rzJllFgHEWa9nXps9Q3aD4/XJp71A==} peerDependencies: @@ -440,72 +496,150 @@ packages: peerDependencies: typescript: '>=5' + '@solana/fast-stable-stringify@2.1.0': + resolution: {integrity: sha512-a8vR92qbe/VsvQ1BpN3PIEwnoHD2fTHEwCJh9GG58z3R15RIjk73gc0khjcdg4U1tZwTJqWkvk8SbDIgGdOgMA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/functional@2.0.0': resolution: {integrity: sha512-Sj+sLiUTimnMEyGnSLGt0lbih2xPDUhxhonnrIkPwA+hjQ3ULGHAxeevHU06nqiVEgENQYUJ5rCtHs4xhUFAkQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/functional@2.1.0': + resolution: {integrity: sha512-RVij8Av4F2uUOFcEC8n9lgD72e9gQMritmGHhMh+G91Xops4I6Few+oQ++XgSTiL2t3g3Cs0QZ13onZ0FL45FQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/instructions@2.0.0': resolution: {integrity: sha512-MiTEiNF7Pzp+Y+x4yadl2VUcNHboaW5WP52psBuhHns3GpbbruRv5efMpM9OEQNe1OsN+Eg39vjEidX55+P+DQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/instructions@2.1.0': + resolution: {integrity: sha512-wfn6e7Rgm0Sw/Th1v/pXsKTvloZvAAQI7j1yc9WcIk9ngqH5p6LhqMMkrwYPB2oTk8+MMr7SZ4E+2eK2gL6ODA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/keys@2.0.0': resolution: {integrity: sha512-SSLSX8BXRvfLKBqsmBghmlhMKpwHeWd5CHi5zXgTS1BRrtiU6lcrTVC9ie6B+WaNNq7oe3e6K5bdbhu3fFZ+0g==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/keys@2.1.0': + resolution: {integrity: sha512-esY1+dlZjB18hZML5p+YPec29wi3HH0SzKx7RiqF//dI2cJ6vHfq3F+7ArbNnF6R2YCLFtl7DzS/tkqR2Xkxeg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + + '@solana/kit@2.1.0': + resolution: {integrity: sha512-vqaHROLKp89xdIbaKVG6BQ44uMN9E6/rSTeltkvquD2qdTObssafGDbAKVFjwZhlNO+sdzHDCLekGabn5VAL6A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/options@2.0.0': resolution: {integrity: sha512-OVc4KnYosB8oAukQ/htgrxXSxlUP6gUu5Aau6d/BgEkPQzWd/Pr+w91VWw3i3zZuu2SGpedbyh05RoJBe/hSXA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/options@2.1.0': + resolution: {integrity: sha512-T/vJCr8qnwK6HxriOPXCrx31IpA9ZYecxuOzQ3G74kIayED4spmpXp6PLtRYR/fo2LZ6UcgHN0qSgONnvwEweg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/programs@2.0.0': resolution: {integrity: sha512-JPIKB61pWfODnsvEAaPALc6vR5rn7kmHLpFaviWhBtfUlEVgB8yVTR0MURe4+z+fJCPRV5wWss+svA4EeGDYzQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/programs@2.1.0': + resolution: {integrity: sha512-9Y30/yUbTR99+QRN2ukNXQQTGY68oKmVrXnh/et6StM1JF5WHvAJqBigsHG5bt6KxTISoRuncBnH/IRnDqPxKg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/promises@2.0.0': resolution: {integrity: sha512-4teQ52HDjK16ORrZe1zl+Q9WcZdQ+YEl0M1gk59XG7D0P9WqaVEQzeXGnKSCs+Y9bnB1u5xCJccwpUhHYWq6gg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/promises@2.1.0': + resolution: {integrity: sha512-eQJaQXA2kD4dVyifzhslV3wOvq27fwOJ4az89BQ4Cz83zPbR94xOeDShwcXrKBYqaUf6XqH5MzdEo14t4tKAFQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-api@2.0.0': resolution: {integrity: sha512-1FwitYxwADMF/6zKP2kNXg8ESxB6GhNBNW1c4f5dEmuXuBbeD/enLV3WMrpg8zJkIaaYarEFNbt7R7HyFzmURQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-api@2.1.0': + resolution: {integrity: sha512-4yCnHYHFlz9VffivoY5q/HVeBjT59byB2gmg7UyC3ktxD28AlF9jjsE5tJKiapAKr2J3KWm0D/rH/QwW14cGeA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-parsed-types@2.0.0': resolution: {integrity: sha512-VCeY/oKVEtBnp8EDOc5LSSiOeIOLFIgLndcxqU0ij/cZaQ01DOoHbhluvhZtU80Z3dUeicec8TiMgkFzed+WhQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-parsed-types@2.1.0': + resolution: {integrity: sha512-mRzHemxlWDS9p1fPQNKwL+1vEOUMG8peSUJb0X/NbM12yjowDNdzM++fkOgIyCKDPddfkcoNmNrQmr2jwjdN1Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-spec-types@2.0.0': resolution: {integrity: sha512-G2lmhFhgtxMQd/D6B04BHGE7bm5dMZdIPQNOqVGhzNAVjrmyapD3JN2hKAbmaYPe97wLfZERw0Ux1u4Y6q7TqA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-spec-types@2.1.0': + resolution: {integrity: sha512-NxcZ8piXMyCdbNUL6d36QJfL2UAQEN33StlGku0ltTVe1nrokZ5WRNjSPohU1fODlNaZzTvUFzvUkM1yGCkyzw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-spec@2.0.0': resolution: {integrity: sha512-1uIDzj7vocCUqfOifjv1zAuxQ53ugiup/42edVFoQLOnJresoEZLL6WjnsJq4oCTccEAvGhUBI1WWKeZTGNxFQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-spec@2.1.0': + resolution: {integrity: sha512-NPAIM5EY7Jke0mHnmoMpgCEb/nZKIo+bgVFK/u+z74gY0JnCNt0DfocStUUQtlhqSmTyoHamt3lfxp4GT2zXbA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-subscriptions-api@2.0.0': resolution: {integrity: sha512-NAJQvSFXYIIf8zxsMFBCkSbZNZgT32pzPZ1V6ZAd+U2iDEjx3L+yFwoJgfOcHp8kAV+alsF2lIsGBlG4u+ehvw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-subscriptions-api@2.1.0': + resolution: {integrity: sha512-de1dBRSE2CUwoZHMXQ/0v7iC+/pG0+iYY8jLHGGNxtKrYbTnV08mXQbaAMrmv2Rk8ZFmfJWbqbYZ9dRWdO3P5g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-subscriptions-channel-websocket@2.0.0': resolution: {integrity: sha512-hSQDZBmcp2t+gLZsSBqs/SqVw4RuNSC7njiP46azyzW7oGg8X2YPV36AHGsHD12KPsc0UpT1OAZ4+AN9meVKww==} engines: {node: '>=20.18.0'} @@ -513,78 +647,157 @@ packages: typescript: '>=5' ws: ^8.18.0 + '@solana/rpc-subscriptions-channel-websocket@2.1.0': + resolution: {integrity: sha512-goJe9dv0cs967HJ382vSX8yapXgQzRHCmH323LsXrrpj/s3Eb3yUwJq7AcHgoh4gKIqyAfGybq/bE5Aa8Pcm9g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + ws: ^8.18.0 + '@solana/rpc-subscriptions-spec@2.0.0': resolution: {integrity: sha512-VXMiI3fYtU1PkVVTXL87pcY48ZY8aCi1N6FqtxSP2xg/GASL01j1qbwyIL1OvoCqGyRgIxdd/YfaByW9wmWBhA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-subscriptions-spec@2.1.0': + resolution: {integrity: sha512-Uqasfd3Tlr22lC/Vy5dToF0e68dMKPdnt4ks7FwXuPdEbNRM/TDGb0GqG+bt/d3IIrNOCA5Y8vsE0nQHGrWG/w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-subscriptions@2.0.0': resolution: {integrity: sha512-AdwMJHMrhlj7q1MPjZmVcKq3iLqMW3N0MT8kzIAP2vP+8o/d6Fn4aqGxoz2Hlfn3OYIZoYStN2VBtwzbcfEgMA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-subscriptions@2.1.0': + resolution: {integrity: sha512-dTyI03VlueE3s7mA/OBlA5l6yKUUKHMJd31tpzxV3AFnqE/QPS5NVrF/WY6pPBobLJiCP0UFOe7eR/MKP9SUCA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-transformers@2.0.0': resolution: {integrity: sha512-H6tN0qcqzUangowsLLQtYXKJsf1Roe3/qJ1Cy0gv9ojY9uEvNbJqpeEj+7blv0MUZfEe+rECAwBhxxRKPMhYGw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-transformers@2.1.0': + resolution: {integrity: sha512-E2xPlaCu6tNO00v4HIJxJCYkoNwgVJYad5sxbIUZOQBWwXnWIcll2jUT4bWKpBGq5vFDYfkzRBr8Rco3DhfXqg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-transport-http@2.0.0': resolution: {integrity: sha512-UJLhKhhxDd1OPi8hb2AenHsDm1mofCBbhWn4bDCnH2Q3ulwYadUhcNqNbxjJPQ774VNhAf53SSI5A6PQo8IZSQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-transport-http@2.1.0': + resolution: {integrity: sha512-E3UovTBid4/S8QDd9FkADVKfyG+v7CW5IqI4c27ZDKfazCsnDLLkqh98C6BvNCqi278HKBui4lI2GoFpCq89Pw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc-types@2.0.0': resolution: {integrity: sha512-o1ApB9PYR0A3XjVSOh//SOVWgjDcqMlR3UNmtqciuREIBmWqnvPirdOa5EJxD3iPhfA4gnNnhGzT+tMDeDW/Kw==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc-types@2.1.0': + resolution: {integrity: sha512-1ODnhmpR1X/GjB7hs4gVR3mcCagfPQV0dzq/2DNuCiMjx2snn64KP5WoAHfBEyoC9/Rb36+JpNj/hLAOikipKA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/rpc@2.0.0': resolution: {integrity: sha512-TumQ9DFRpib/RyaIqLVfr7UjqSo7ldfzpae0tgjM93YjbItB4Z0VcUXc3uAFvkeYw2/HIMb46Zg43mkUwozjDg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/rpc@2.1.0': + resolution: {integrity: sha512-myg9qAo6b2WKyHSMXURQykb+ZRnNEXBPLEcwRwkos8STzPPyRFg6ady2s0FCQQTtL/pVjanIU2bObZIzbMGugA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/signers@2.0.0': resolution: {integrity: sha512-JEYJS3x/iKkqPV/3b1nLpX9lHib21wQKV3fOuu1aDLQqmX9OYKrnIIITYdnFDhmvGhpEpkkbPnqu7yVaFIBYsQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/signers@2.1.0': + resolution: {integrity: sha512-Yq0JdJnCecRsSBshNWy+OIRmAGeVfjwIh9Z+H1jv8u8p+dJCOreKakTWuxMt5tnj3q5K1mPcak9O2PqVPZ0teA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/subscribable@2.0.0': resolution: {integrity: sha512-Ex7d2GnTSNVMZDU3z6nKN4agRDDgCgBDiLnmn1hmt0iFo3alr3gRAqiqa7qGouAtYh9/29pyc8tVJCijHWJPQQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/subscribable@2.1.0': + resolution: {integrity: sha512-xi12Cm889+uT5sRKnIzr7nLnHAp3hiR3dqIzrT1P7z7iEGp8OnqUQIQCHlgozFHM2cPW+6685NQXk1l1ImuJIw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/sysvars@2.0.0': resolution: {integrity: sha512-8D4ajKcCYQsTG1p4k30lre2vjxLR6S5MftUGJnIaQObDCzGmaeA9GRti4Kk4gSPWVYFTBoj1ASx8EcEXaB3eIQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/sysvars@2.1.0': + resolution: {integrity: sha512-GXu9yS0zIebmM1Unqw/XFpYuvug03m42w98ioOPV/yiHzECggGRGpHGD9RLVYnkyz0eL4NRbnJ5dAEu/fvGe0A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/transaction-confirmation@2.0.0': resolution: {integrity: sha512-JkTw5gXLiqQjf6xK0fpVcoJ/aMp2kagtFSD/BAOazdJ3UYzOzbzqvECt6uWa3ConcMswQ2vXalVtI7ZjmYuIeg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/transaction-confirmation@2.1.0': + resolution: {integrity: sha512-VxOvtvs2e9h5u73PHyE2TptLAMO5x6dOXlOgvq1Nk6l3rKM2HAsd+KDpN7gjOo8/EgItMMmyEilXygWWRgpSIA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/transaction-messages@2.0.0': resolution: {integrity: sha512-Uc6Fw1EJLBrmgS1lH2ZfLAAKFvprWPQQzOVwZS78Pv8Whsk7tweYTK6S0Upv0nHr50rGpnORJfmdBrXE6OfNGg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/transaction-messages@2.1.0': + resolution: {integrity: sha512-+GPzZHLYNFbqHKoiL8mYALp7eAXtAbI6zLViZpIM3zUbVNU3q5+FCKGv6jCBnxs+3QCbeapu+W1OyfDa6BUtTQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/transactions@2.0.0': resolution: {integrity: sha512-VfdTE+59WKvuBG//6iE9RPjAB+ZT2kLgY2CDHabaz6RkH6OjOkMez9fWPVa3Xtcus+YQWN1SnQoryjF/xSx04w==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' + '@solana/transactions@2.1.0': + resolution: {integrity: sha512-QeM4sCItReeIy5LU7LhGkz7RPfMPTg/Qo8h0LSfhiJiPTOHOhElmh42vkLJmwPl83+MsKtisyPQNK6penM2nAw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@solana/web3.js@2.0.0': resolution: {integrity: sha512-x+ZRB2/r5tVK/xw8QRbAfgPcX51G9f2ifEyAQ/J5npOO+6+MPeeCjtr5UxHNDAYs9Ypo0PN+YJATCO4vhzQJGg==} engines: {node: '>=20.18.0'} @@ -903,6 +1116,10 @@ packages: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1926,6 +2143,9 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@7.4.0: + resolution: {integrity: sha512-4tv8DA1nBRW5kF2KBJZzEBjd66kDf3jArNVPoktdlv9Xsgw7EcIMu1bVbAXbX5IWuuZZ3YW3jIM2x85SPgMP6w==} + unicorn-magic@0.1.0: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} engines: {node: '>=18'} @@ -2262,6 +2482,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/accounts@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec': 2.1.0(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/addresses@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/assertions': 2.0.0(typescript@5.5.3) @@ -2272,16 +2504,36 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/addresses@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/assertions': 2.1.0(typescript@5.5.3) + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/assertions@2.0.0(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 + '@solana/assertions@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + '@solana/codecs-core@2.0.0(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 + '@solana/codecs-core@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + '@solana/codecs-data-structures@2.0.0(typescript@5.5.3)': dependencies: '@solana/codecs-core': 2.0.0(typescript@5.5.3) @@ -2289,12 +2541,25 @@ snapshots: '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 + '@solana/codecs-data-structures@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.1.0(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + '@solana/codecs-numbers@2.0.0(typescript@5.5.3)': dependencies: '@solana/codecs-core': 2.0.0(typescript@5.5.3) '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 + '@solana/codecs-numbers@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + '@solana/codecs-strings@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/codecs-core': 2.0.0(typescript@5.5.3) @@ -2303,6 +2568,14 @@ snapshots: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.5.3 + '@solana/codecs-strings@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.1.0(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.5.3 + '@solana/codecs@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/codecs-core': 2.0.0(typescript@5.5.3) @@ -2314,12 +2587,29 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/codecs@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.1.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.1.0(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/options': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/errors@2.0.0(typescript@5.5.3)': dependencies: chalk: 5.3.0 commander: 12.1.0 typescript: 5.5.3 + '@solana/errors@2.1.0(typescript@5.5.3)': + dependencies: + chalk: 5.3.0 + commander: 13.1.0 + typescript: 5.5.3 + '@solana/eslint-config-solana@3.0.3(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-simple-import-sort@10.0.0(eslint@8.57.0))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.2.0(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)': dependencies: '@typescript-eslint/eslint-plugin': 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) @@ -2336,15 +2626,29 @@ snapshots: dependencies: typescript: 5.5.3 + '@solana/fast-stable-stringify@2.1.0(typescript@5.5.3)': + dependencies: + typescript: 5.5.3 + '@solana/functional@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 + '@solana/functional@2.1.0(typescript@5.5.3)': + dependencies: + typescript: 5.5.3 + '@solana/instructions@2.0.0(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 + '@solana/instructions@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + '@solana/keys@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/assertions': 2.0.0(typescript@5.5.3) @@ -2355,6 +2659,41 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/keys@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/assertions': 2.1.0(typescript@5.5.3) + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/accounts': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/functional': 2.1.0(typescript@5.5.3) + '@solana/instructions': 2.1.0(typescript@5.5.3) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/programs': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-parsed-types': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.1.0(typescript@5.5.3) + '@solana/rpc-subscriptions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/signers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/sysvars': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-confirmation': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/options@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/codecs-core': 2.0.0(typescript@5.5.3) @@ -2366,6 +2705,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/options@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.1.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.1.0(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/programs@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2374,10 +2724,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/programs@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/promises@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 + '@solana/promises@2.1.0(typescript@5.5.3)': + dependencies: + typescript: 5.5.3 + '@solana/rpc-api@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2395,20 +2757,51 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-api@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-parsed-types': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec': 2.1.0(typescript@5.5.3) + '@solana/rpc-transformers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-parsed-types@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 + '@solana/rpc-parsed-types@2.1.0(typescript@5.5.3)': + dependencies: + typescript: 5.5.3 + '@solana/rpc-spec-types@2.0.0(typescript@5.5.3)': dependencies: typescript: 5.5.3 + '@solana/rpc-spec-types@2.1.0(typescript@5.5.3)': + dependencies: + typescript: 5.5.3 + '@solana/rpc-spec@2.0.0(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) '@solana/rpc-spec-types': 2.0.0(typescript@5.5.3) typescript: 5.5.3 + '@solana/rpc-spec@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + '@solana/rpc-subscriptions-api@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2422,6 +2815,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-api@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions-spec': 2.1.0(typescript@5.5.3) + '@solana/rpc-transformers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-channel-websocket@2.0.0(typescript@5.5.3)(ws@8.17.0)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) @@ -2431,6 +2837,15 @@ snapshots: typescript: 5.5.3 ws: 8.17.0 + '@solana/rpc-subscriptions-channel-websocket@2.1.0(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/functional': 2.1.0(typescript@5.5.3) + '@solana/rpc-subscriptions-spec': 2.1.0(typescript@5.5.3) + '@solana/subscribable': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + ws: 8.17.0 + '@solana/rpc-subscriptions-spec@2.0.0(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) @@ -2439,6 +2854,14 @@ snapshots: '@solana/subscribable': 2.0.0(typescript@5.5.3) typescript: 5.5.3 + '@solana/rpc-subscriptions-spec@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/promises': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.1.0(typescript@5.5.3) + '@solana/subscribable': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + '@solana/rpc-subscriptions@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) @@ -2457,6 +2880,24 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/rpc-subscriptions@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/fast-stable-stringify': 2.1.0(typescript@5.5.3) + '@solana/functional': 2.1.0(typescript@5.5.3) + '@solana/promises': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.1.0(typescript@5.5.3) + '@solana/rpc-subscriptions-api': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions-channel-websocket': 2.1.0(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-subscriptions-spec': 2.1.0(typescript@5.5.3) + '@solana/rpc-transformers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/subscribable': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/rpc-transformers@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) @@ -2467,6 +2908,16 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-transformers@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/functional': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.1.0(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-transport-http@2.0.0(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) @@ -2475,6 +2926,14 @@ snapshots: typescript: 5.5.3 undici-types: 6.20.0 + '@solana/rpc-transport-http@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + undici-types: 7.4.0 + '@solana/rpc-types@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2486,6 +2945,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-types@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.1.0(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) @@ -2501,6 +2971,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/fast-stable-stringify': 2.1.0(typescript@5.5.3) + '@solana/functional': 2.1.0(typescript@5.5.3) + '@solana/rpc-api': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-spec': 2.1.0(typescript@5.5.3) + '@solana/rpc-spec-types': 2.1.0(typescript@5.5.3) + '@solana/rpc-transformers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-transport-http': 2.1.0(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/signers@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2514,11 +2999,29 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/signers@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/instructions': 2.1.0(typescript@5.5.3) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/subscribable@2.0.0(typescript@5.5.3)': dependencies: '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 + '@solana/subscribable@2.1.0(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.1.0(typescript@5.5.3) + typescript: 5.5.3 + '@solana/sysvars@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/accounts': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2529,6 +3032,16 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/accounts': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transaction-confirmation@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2546,6 +3059,23 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/transaction-confirmation@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/promises': 2.1.0(typescript@5.5.3) + '@solana/rpc': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-subscriptions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/transaction-messages@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2560,6 +3090,20 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.1.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.1.0(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/functional': 2.1.0(typescript@5.5.3) + '@solana/instructions': 2.1.0(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transactions@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2577,6 +3121,23 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transactions@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/codecs-core': 2.1.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.1.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.1.0(typescript@5.5.3) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.1.0(typescript@5.5.3) + '@solana/functional': 2.1.0(typescript@5.5.3) + '@solana/instructions': 2.1.0(typescript@5.5.3) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)(ws@8.17.0)': dependencies: '@solana/accounts': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) @@ -2975,6 +3536,8 @@ snapshots: commander@12.1.0: {} + commander@13.1.0: {} + commander@4.1.1: {} common-path-prefix@3.0.0: {} @@ -3942,6 +4505,8 @@ snapshots: undici-types@6.20.0: {} + undici-types@7.4.0: {} + unicorn-magic@0.1.0: {} uri-js@4.4.1: diff --git a/clients/js/src/generated/accounts/mint.ts b/clients/js/src/generated/accounts/mint.ts index 5b173bd..cdd32ef 100644 --- a/clients/js/src/generated/accounts/mint.ts +++ b/clients/js/src/generated/accounts/mint.ts @@ -39,7 +39,7 @@ import { type MaybeEncodedAccount, type Option, type OptionOrNullable, -} from '@solana/web3.js'; +} from '@solana/kit'; export type Mint = { /** diff --git a/clients/js/src/generated/accounts/multisig.ts b/clients/js/src/generated/accounts/multisig.ts index 066bf91..91377b4 100644 --- a/clients/js/src/generated/accounts/multisig.ts +++ b/clients/js/src/generated/accounts/multisig.ts @@ -33,7 +33,7 @@ import { type FetchAccountsConfig, type MaybeAccount, type MaybeEncodedAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; export type Multisig = { /** Number of signers required. */ diff --git a/clients/js/src/generated/accounts/token.ts b/clients/js/src/generated/accounts/token.ts index 278baa0..04e41b4 100644 --- a/clients/js/src/generated/accounts/token.ts +++ b/clients/js/src/generated/accounts/token.ts @@ -35,7 +35,7 @@ import { type MaybeEncodedAccount, type Option, type OptionOrNullable, -} from '@solana/web3.js'; +} from '@solana/kit'; import { getAccountStateDecoder, getAccountStateEncoder, diff --git a/clients/js/src/generated/errors/associatedToken.ts b/clients/js/src/generated/errors/associatedToken.ts index c651725..beda155 100644 --- a/clients/js/src/generated/errors/associatedToken.ts +++ b/clients/js/src/generated/errors/associatedToken.ts @@ -11,7 +11,7 @@ import { type Address, type SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM, type SolanaError, -} from '@solana/web3.js'; +} from '@solana/kit'; import { ASSOCIATED_TOKEN_PROGRAM_ADDRESS } from '../programs'; /** InvalidOwner: Associated token account owner does not match address derivation */ diff --git a/clients/js/src/generated/errors/token.ts b/clients/js/src/generated/errors/token.ts index 9afda17..1a9624e 100644 --- a/clients/js/src/generated/errors/token.ts +++ b/clients/js/src/generated/errors/token.ts @@ -11,7 +11,7 @@ import { type Address, type SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM, type SolanaError, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; /** NotRentExempt: Lamport balance below rent-exempt threshold */ diff --git a/clients/js/src/generated/instructions/amountToUiAmount.ts b/clients/js/src/generated/instructions/amountToUiAmount.ts index 4aa8240..97fbbde 100644 --- a/clients/js/src/generated/instructions/amountToUiAmount.ts +++ b/clients/js/src/generated/instructions/amountToUiAmount.ts @@ -24,7 +24,7 @@ import { type IInstructionWithAccounts, type IInstructionWithData, type ReadonlyAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/approve.ts b/clients/js/src/generated/instructions/approve.ts index f2deaed..e73cb65 100644 --- a/clients/js/src/generated/instructions/approve.ts +++ b/clients/js/src/generated/instructions/approve.ts @@ -29,7 +29,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/approveChecked.ts b/clients/js/src/generated/instructions/approveChecked.ts index 1e37bfa..6179390 100644 --- a/clients/js/src/generated/instructions/approveChecked.ts +++ b/clients/js/src/generated/instructions/approveChecked.ts @@ -29,7 +29,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/burn.ts b/clients/js/src/generated/instructions/burn.ts index bb15b37..149a865 100644 --- a/clients/js/src/generated/instructions/burn.ts +++ b/clients/js/src/generated/instructions/burn.ts @@ -29,7 +29,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/burnChecked.ts b/clients/js/src/generated/instructions/burnChecked.ts index 6f137e6..88ed2f1 100644 --- a/clients/js/src/generated/instructions/burnChecked.ts +++ b/clients/js/src/generated/instructions/burnChecked.ts @@ -29,7 +29,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/closeAccount.ts b/clients/js/src/generated/instructions/closeAccount.ts index 7973bd4..3237931 100644 --- a/clients/js/src/generated/instructions/closeAccount.ts +++ b/clients/js/src/generated/instructions/closeAccount.ts @@ -27,7 +27,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/createAssociatedToken.ts b/clients/js/src/generated/instructions/createAssociatedToken.ts index e24ec53..371bcf2 100644 --- a/clients/js/src/generated/instructions/createAssociatedToken.ts +++ b/clients/js/src/generated/instructions/createAssociatedToken.ts @@ -26,7 +26,7 @@ import { type TransactionSigner, type WritableAccount, type WritableSignerAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { findAssociatedTokenPda } from '../pdas'; import { ASSOCIATED_TOKEN_PROGRAM_ADDRESS } from '../programs'; import { diff --git a/clients/js/src/generated/instructions/createAssociatedTokenIdempotent.ts b/clients/js/src/generated/instructions/createAssociatedTokenIdempotent.ts index a0216da..032f68f 100644 --- a/clients/js/src/generated/instructions/createAssociatedTokenIdempotent.ts +++ b/clients/js/src/generated/instructions/createAssociatedTokenIdempotent.ts @@ -26,7 +26,7 @@ import { type TransactionSigner, type WritableAccount, type WritableSignerAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { findAssociatedTokenPda } from '../pdas'; import { ASSOCIATED_TOKEN_PROGRAM_ADDRESS } from '../programs'; import { diff --git a/clients/js/src/generated/instructions/freezeAccount.ts b/clients/js/src/generated/instructions/freezeAccount.ts index 6dfc214..fe7ba71 100644 --- a/clients/js/src/generated/instructions/freezeAccount.ts +++ b/clients/js/src/generated/instructions/freezeAccount.ts @@ -27,7 +27,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/getAccountDataSize.ts b/clients/js/src/generated/instructions/getAccountDataSize.ts index 098aee0..f9d3672 100644 --- a/clients/js/src/generated/instructions/getAccountDataSize.ts +++ b/clients/js/src/generated/instructions/getAccountDataSize.ts @@ -22,7 +22,7 @@ import { type IInstructionWithAccounts, type IInstructionWithData, type ReadonlyAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/initializeAccount.ts b/clients/js/src/generated/instructions/initializeAccount.ts index 8ea41c8..b9ea3ab 100644 --- a/clients/js/src/generated/instructions/initializeAccount.ts +++ b/clients/js/src/generated/instructions/initializeAccount.ts @@ -23,7 +23,7 @@ import { type IInstructionWithData, type ReadonlyAccount, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/initializeAccount2.ts b/clients/js/src/generated/instructions/initializeAccount2.ts index 204e0d4..1818d2e 100644 --- a/clients/js/src/generated/instructions/initializeAccount2.ts +++ b/clients/js/src/generated/instructions/initializeAccount2.ts @@ -25,7 +25,7 @@ import { type IInstructionWithData, type ReadonlyAccount, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/initializeAccount3.ts b/clients/js/src/generated/instructions/initializeAccount3.ts index e10ce5a..2cdd4d6 100644 --- a/clients/js/src/generated/instructions/initializeAccount3.ts +++ b/clients/js/src/generated/instructions/initializeAccount3.ts @@ -25,7 +25,7 @@ import { type IInstructionWithData, type ReadonlyAccount, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/initializeImmutableOwner.ts b/clients/js/src/generated/instructions/initializeImmutableOwner.ts index a25d85c..14e9b3a 100644 --- a/clients/js/src/generated/instructions/initializeImmutableOwner.ts +++ b/clients/js/src/generated/instructions/initializeImmutableOwner.ts @@ -22,7 +22,7 @@ import { type IInstructionWithAccounts, type IInstructionWithData, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/initializeMint.ts b/clients/js/src/generated/instructions/initializeMint.ts index ea070d8..4c45660 100644 --- a/clients/js/src/generated/instructions/initializeMint.ts +++ b/clients/js/src/generated/instructions/initializeMint.ts @@ -30,7 +30,7 @@ import { type OptionOrNullable, type ReadonlyAccount, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/initializeMint2.ts b/clients/js/src/generated/instructions/initializeMint2.ts index cc5595f..cb00138 100644 --- a/clients/js/src/generated/instructions/initializeMint2.ts +++ b/clients/js/src/generated/instructions/initializeMint2.ts @@ -29,7 +29,7 @@ import { type Option, type OptionOrNullable, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/initializeMultisig.ts b/clients/js/src/generated/instructions/initializeMultisig.ts index 032af70..7314f4a 100644 --- a/clients/js/src/generated/instructions/initializeMultisig.ts +++ b/clients/js/src/generated/instructions/initializeMultisig.ts @@ -24,7 +24,7 @@ import { type IInstructionWithData, type ReadonlyAccount, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/initializeMultisig2.ts b/clients/js/src/generated/instructions/initializeMultisig2.ts index 54fb35e..36891e1 100644 --- a/clients/js/src/generated/instructions/initializeMultisig2.ts +++ b/clients/js/src/generated/instructions/initializeMultisig2.ts @@ -23,7 +23,7 @@ import { type IInstructionWithAccounts, type IInstructionWithData, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/mintTo.ts b/clients/js/src/generated/instructions/mintTo.ts index a64205b..cc9f473 100644 --- a/clients/js/src/generated/instructions/mintTo.ts +++ b/clients/js/src/generated/instructions/mintTo.ts @@ -29,7 +29,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/mintToChecked.ts b/clients/js/src/generated/instructions/mintToChecked.ts index 0b0e03b..8983d52 100644 --- a/clients/js/src/generated/instructions/mintToChecked.ts +++ b/clients/js/src/generated/instructions/mintToChecked.ts @@ -29,7 +29,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/recoverNestedAssociatedToken.ts b/clients/js/src/generated/instructions/recoverNestedAssociatedToken.ts index bc106ac..b09cfaf 100644 --- a/clients/js/src/generated/instructions/recoverNestedAssociatedToken.ts +++ b/clients/js/src/generated/instructions/recoverNestedAssociatedToken.ts @@ -26,7 +26,7 @@ import { type TransactionSigner, type WritableAccount, type WritableSignerAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { findAssociatedTokenPda } from '../pdas'; import { ASSOCIATED_TOKEN_PROGRAM_ADDRESS } from '../programs'; import { diff --git a/clients/js/src/generated/instructions/revoke.ts b/clients/js/src/generated/instructions/revoke.ts index bc37b6e..caf2caa 100644 --- a/clients/js/src/generated/instructions/revoke.ts +++ b/clients/js/src/generated/instructions/revoke.ts @@ -27,7 +27,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/setAuthority.ts b/clients/js/src/generated/instructions/setAuthority.ts index 21bbc8d..ea97f03 100644 --- a/clients/js/src/generated/instructions/setAuthority.ts +++ b/clients/js/src/generated/instructions/setAuthority.ts @@ -33,7 +33,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; import { diff --git a/clients/js/src/generated/instructions/syncNative.ts b/clients/js/src/generated/instructions/syncNative.ts index b9b6b29..924051e 100644 --- a/clients/js/src/generated/instructions/syncNative.ts +++ b/clients/js/src/generated/instructions/syncNative.ts @@ -22,7 +22,7 @@ import { type IInstructionWithAccounts, type IInstructionWithData, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/thawAccount.ts b/clients/js/src/generated/instructions/thawAccount.ts index af35469..dbc5885 100644 --- a/clients/js/src/generated/instructions/thawAccount.ts +++ b/clients/js/src/generated/instructions/thawAccount.ts @@ -27,7 +27,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/transfer.ts b/clients/js/src/generated/instructions/transfer.ts index e9b95ed..8631270 100644 --- a/clients/js/src/generated/instructions/transfer.ts +++ b/clients/js/src/generated/instructions/transfer.ts @@ -29,7 +29,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/transferChecked.ts b/clients/js/src/generated/instructions/transferChecked.ts index 44b6fa7..c2ae46e 100644 --- a/clients/js/src/generated/instructions/transferChecked.ts +++ b/clients/js/src/generated/instructions/transferChecked.ts @@ -29,7 +29,7 @@ import { type ReadonlySignerAccount, type TransactionSigner, type WritableAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/instructions/uiAmountToAmount.ts b/clients/js/src/generated/instructions/uiAmountToAmount.ts index 3700571..4437569 100644 --- a/clients/js/src/generated/instructions/uiAmountToAmount.ts +++ b/clients/js/src/generated/instructions/uiAmountToAmount.ts @@ -24,7 +24,7 @@ import { type IInstructionWithAccounts, type IInstructionWithData, type ReadonlyAccount, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; diff --git a/clients/js/src/generated/pdas/associatedToken.ts b/clients/js/src/generated/pdas/associatedToken.ts index f9704a9..2ccb314 100644 --- a/clients/js/src/generated/pdas/associatedToken.ts +++ b/clients/js/src/generated/pdas/associatedToken.ts @@ -11,7 +11,7 @@ import { getProgramDerivedAddress, type Address, type ProgramDerivedAddress, -} from '@solana/web3.js'; +} from '@solana/kit'; export type AssociatedTokenSeeds = { /** The wallet address of the associated token account. */ diff --git a/clients/js/src/generated/programs/associatedToken.ts b/clients/js/src/generated/programs/associatedToken.ts index b5efc1c..5c3e132 100644 --- a/clients/js/src/generated/programs/associatedToken.ts +++ b/clients/js/src/generated/programs/associatedToken.ts @@ -11,7 +11,7 @@ import { getU8Encoder, type Address, type ReadonlyUint8Array, -} from '@solana/web3.js'; +} from '@solana/kit'; import { type ParsedCreateAssociatedTokenIdempotentInstruction, type ParsedCreateAssociatedTokenInstruction, diff --git a/clients/js/src/generated/programs/token.ts b/clients/js/src/generated/programs/token.ts index 016a2ad..dc17fc3 100644 --- a/clients/js/src/generated/programs/token.ts +++ b/clients/js/src/generated/programs/token.ts @@ -11,7 +11,7 @@ import { getU8Encoder, type Address, type ReadonlyUint8Array, -} from '@solana/web3.js'; +} from '@solana/kit'; import { type ParsedAmountToUiAmountInstruction, type ParsedApproveCheckedInstruction, diff --git a/clients/js/src/generated/shared/index.ts b/clients/js/src/generated/shared/index.ts index 01a7d93..7ba9053 100644 --- a/clients/js/src/generated/shared/index.ts +++ b/clients/js/src/generated/shared/index.ts @@ -9,14 +9,14 @@ import { AccountRole, isProgramDerivedAddress, - isTransactionSigner as web3JsIsTransactionSigner, + isTransactionSigner as kitIsTransactionSigner, type Address, type IAccountMeta, type IAccountSignerMeta, type ProgramDerivedAddress, type TransactionSigner, upgradeRoleToSigner, -} from '@solana/web3.js'; +} from '@solana/kit'; /** * Asserts that the given value is not null or undefined. @@ -159,6 +159,6 @@ export function isTransactionSigner( !!value && typeof value === 'object' && 'address' in value && - web3JsIsTransactionSigner(value) + kitIsTransactionSigner(value) ); } diff --git a/clients/js/src/generated/types/accountState.ts b/clients/js/src/generated/types/accountState.ts index d113ca4..a870212 100644 --- a/clients/js/src/generated/types/accountState.ts +++ b/clients/js/src/generated/types/accountState.ts @@ -13,7 +13,7 @@ import { type Codec, type Decoder, type Encoder, -} from '@solana/web3.js'; +} from '@solana/kit'; export enum AccountState { Uninitialized, diff --git a/clients/js/src/generated/types/authorityType.ts b/clients/js/src/generated/types/authorityType.ts index 826ae17..795acad 100644 --- a/clients/js/src/generated/types/authorityType.ts +++ b/clients/js/src/generated/types/authorityType.ts @@ -13,7 +13,7 @@ import { type Codec, type Decoder, type Encoder, -} from '@solana/web3.js'; +} from '@solana/kit'; export enum AuthorityType { MintTokens, diff --git a/clients/js/test/_setup.ts b/clients/js/test/_setup.ts index 4a35fc0..bc9629b 100644 --- a/clients/js/test/_setup.ts +++ b/clients/js/test/_setup.ts @@ -22,7 +22,7 @@ import { setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners, -} from '@solana/web3.js'; +} from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS, getInitializeAccountInstruction, diff --git a/clients/js/test/createAssociatedToken.test.ts b/clients/js/test/createAssociatedToken.test.ts index 6a5177c..787b14f 100644 --- a/clients/js/test/createAssociatedToken.test.ts +++ b/clients/js/test/createAssociatedToken.test.ts @@ -4,7 +4,7 @@ import { generateKeyPairSigner, none, pipe, -} from '@solana/web3.js'; +} from '@solana/kit'; import test from 'ava'; import { AccountState, diff --git a/clients/js/test/createAssociatedTokenIdempotent.test.ts b/clients/js/test/createAssociatedTokenIdempotent.test.ts index 0d0051d..4860712 100644 --- a/clients/js/test/createAssociatedTokenIdempotent.test.ts +++ b/clients/js/test/createAssociatedTokenIdempotent.test.ts @@ -4,7 +4,7 @@ import { generateKeyPairSigner, none, pipe, -} from '@solana/web3.js'; +} from '@solana/kit'; import test from 'ava'; import { AccountState, diff --git a/clients/js/test/initializeAccount.test.ts b/clients/js/test/initializeAccount.test.ts index a897a8d..30a3782 100644 --- a/clients/js/test/initializeAccount.test.ts +++ b/clients/js/test/initializeAccount.test.ts @@ -5,7 +5,7 @@ import { generateKeyPairSigner, none, pipe, -} from '@solana/web3.js'; +} from '@solana/kit'; import test from 'ava'; import { AccountState, diff --git a/clients/js/test/initializeMint.test.ts b/clients/js/test/initializeMint.test.ts index 0d2791c..a12d4b8 100644 --- a/clients/js/test/initializeMint.test.ts +++ b/clients/js/test/initializeMint.test.ts @@ -6,7 +6,7 @@ import { none, pipe, some, -} from '@solana/web3.js'; +} from '@solana/kit'; import test from 'ava'; import { Mint, diff --git a/clients/js/test/mintTo.test.ts b/clients/js/test/mintTo.test.ts index 870191c..e1af4f9 100644 --- a/clients/js/test/mintTo.test.ts +++ b/clients/js/test/mintTo.test.ts @@ -2,7 +2,7 @@ import { appendTransactionMessageInstruction, generateKeyPairSigner, pipe, -} from '@solana/web3.js'; +} from '@solana/kit'; import test from 'ava'; import { Mint, diff --git a/clients/js/test/transfer.test.ts b/clients/js/test/transfer.test.ts index 4f0f9df..d98b145 100644 --- a/clients/js/test/transfer.test.ts +++ b/clients/js/test/transfer.test.ts @@ -2,7 +2,7 @@ import { appendTransactionMessageInstruction, generateKeyPairSigner, pipe, -} from '@solana/web3.js'; +} from '@solana/kit'; import test from 'ava'; import { Mint, diff --git a/package.json b/package.json index 9a3d3fb..412f6a8 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,10 @@ "rust:semver": "cargo semver-checks" }, "devDependencies": { - "@codama/renderers-js": "^1.0.0", - "@codama/renderers-rust": "^1.0.0", + "@codama/renderers-js": "^1.2.7", + "@codama/renderers-rust": "^1.0.16", "@iarna/toml": "^2.2.5", - "codama": "^1.0.0", + "codama": "^1.2.8", "typescript": "^5.5.2", "zx": "^7.2.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b063c59..806dd1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,17 +9,17 @@ importers: .: devDependencies: '@codama/renderers-js': - specifier: ^1.0.0 - version: 1.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + specifier: ^1.2.7 + version: 1.2.7(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) '@codama/renderers-rust': - specifier: ^1.0.0 - version: 1.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + specifier: ^1.0.16 + version: 1.0.16(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) '@iarna/toml': specifier: ^2.2.5 version: 2.2.5 codama: - specifier: ^1.0.0 - version: 1.0.0 + specifier: ^1.2.8 + version: 1.2.8(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) typescript: specifier: ^5.5.2 version: 5.5.3 @@ -29,42 +29,51 @@ importers: packages: - '@codama/errors@1.0.0': - resolution: {integrity: sha512-XSdkNbCNJukhKO5TFJ5cFP7TfddxZwqHV7N/XyMbZ0meVPN1ymT94/d/9b8R+bvKuflj/SXImv527tGZWz6pGA==} + '@codama/cli@1.0.7': + resolution: {integrity: sha512-qA+cDhTnx3r4Ds9JAIduGTzaEJjjCSVj+Bt2mm1hEW1hrI4hymAxW+BeLfFehzqjggdTVM3UIrTwkXAkhNJfEw==} + + '@codama/errors@1.2.8': + resolution: {integrity: sha512-TVPf7oJpbHtxdu52ruftJX+DlTNWi7D65tasysqs7mfRKoiZKzmkatr5hqidBz/M9WzCddUeFAHL9ZiW6g9Ccg==} hasBin: true - '@codama/node-types@1.0.0': - resolution: {integrity: sha512-UAc+0jprwHFOqtAPqqA//PkrnlUzuqs+N5E36bHhLV0m5qWMlqrfmPg/ffBwMYFJsLFWsRsisALrqPy7ARkUow==} + '@codama/node-types@1.2.8': + resolution: {integrity: sha512-PEvPLMN3QGJvkwsQ7R9DmAtdazQXN0RD9WYlmHyeiR4nathV0qy9nZGFDoRh5nbNfPkbeLTgL5o3zAoeeRP6GQ==} + + '@codama/nodes-from-anchor@1.1.8': + resolution: {integrity: sha512-eaoGrcMMc5yr1XPnv1H3hPw6cCh0e6BRmmuzOBOIDG4PR2gVm415RnBkfQOX2JqRTX7wKLv8Y1EIZV4IgVxkvw==} + + '@codama/nodes@1.2.8': + resolution: {integrity: sha512-tCi7KErG2ChQr5n3Nj3dwciFmUo3O8RQ+S4Qv23w1zvYLaGwhEvdg3KRtgCGEI0wr9uvm2QtTBM670kdLntZiQ==} - '@codama/nodes-from-anchor@1.0.0': - resolution: {integrity: sha512-urqFOV5K1oKBptgIFFLCPWrUsEeZsonml12ieP26ozX12aglGlN0tsxNsCvxJulRIjUxuONbH6xzv7uKt0xSYQ==} + '@codama/renderers-core@1.0.10': + resolution: {integrity: sha512-7NwoyP2j1cZKgHCrd1RRn891gtxpZeiXNSP3aCFdVsRPW8dDNUL1sJ1SNOF9ILHfNP77clCBtL3eoZIFdeNQAg==} - '@codama/nodes@1.0.0': - resolution: {integrity: sha512-btcnjDaOpEFvVq3uVzlQK4G2OxxyK3P9HkXw423GZaqYQzeSr1pDdTKjyVyg+QO578CGqIMySVlJ2UAdHVMytw==} + '@codama/renderers-js-umi@1.1.9': + resolution: {integrity: sha512-rYrm1u3zqqHfYtLnnYmhU+4KXYCqmGJxQP+eiyHIDwxcALzH6y8Ng2zEz3YRGNLXqdlwCB4bx1lJOCjfbRZiwA==} - '@codama/renderers-core@1.0.0': - resolution: {integrity: sha512-WYvOylIzcR0WOc7GlUvGi5ym8IwmslwyV8zfj7FR646bMqaROirFJc+naGEbZ1lMykOyxcackTKL0eDB7954Qw==} + '@codama/renderers-js@1.2.7': + resolution: {integrity: sha512-xzWK7tdPneNhbPAMeh5B4ddXjMfkNtTbDDRJ81jNvGv8WRPCvA97c0zMeTskHY+W/C+GlbsSNGMuL4Ga8bEmSA==} - '@codama/renderers-js@1.0.0': - resolution: {integrity: sha512-wi9eqrtLbTM49ELqKqxIgbTaf7xKMWT+HIqj6GN373G0OJnSKwUJPIXAGLO+RCls5DGjDuOE5svuThU0zBkfzA==} + '@codama/renderers-rust@1.0.16': + resolution: {integrity: sha512-pFHwHN6X4Yuk26Yfh+VT9Ps1i/QEjuK3EoT8BpsCTATOk6ntJNqyD5aQngG2lE4KWx3uQrCYYbQEAN4vG6v+EA==} - '@codama/renderers-rust@1.0.0': - resolution: {integrity: sha512-2z+XN6KCTQFDfE30OQcRo2LW4+9dnYlqs8rSUhKO2YsRiCnOoMu/zrNSqLtjL84T2PAwReRq+vBifcE0zaOuRw==} + '@codama/renderers@1.0.16': + resolution: {integrity: sha512-Mj3k1BJ7Rg9BlaCNCvhWY+FRmgLnislwatA6t9zHiReSeukrOFmSW9KKPpWHXm4+i1ueZFKmLeFzGPEt927WBA==} - '@codama/validators@1.0.0': - resolution: {integrity: sha512-jSfU5IrcGTvcqsJSBSzD3Ochig+hKKg2NKsT/vUfQ4jAw2cQrVUP5f4dMXyX779JYfHLHCwZnBYvgEdgi9gBZQ==} + '@codama/validators@1.2.8': + resolution: {integrity: sha512-cGyYgV+zhPzhT3RHBKgDLueeOvSTo3ry9QEliPv90+sL6Q9ecKj4Ut9QVxjmwvdv67rNAZq5JBl+GC8SYcDhPg==} - '@codama/visitors-core@1.0.0': - resolution: {integrity: sha512-tDIfURVPf7ZokCFLOpKL6Au0ORiza1sPT4zmRSEjCC7iZp0Vb5K5FrdtUL13Wb+6jNM191e5GUFOmULRoavWug==} + '@codama/visitors-core@1.2.8': + resolution: {integrity: sha512-sYmZT2Z6Goacgr/HrAhjLSGtu2Udcal10tEfYN8ZJBXs34PGPu0oWOC8kFx7CxvmAvt/6mw8NhKIPtg/UaIKHw==} - '@codama/visitors@1.0.0': - resolution: {integrity: sha512-JncE6wRJLxt0imlj+loGH6dLPEMK7ozlv9YjWgCQgUYUI7is66OFwhWP5SFO0iEFlVjtOzZLXVQwoe9LSDz8Gg==} + '@codama/visitors@1.2.8': + resolution: {integrity: sha512-LbcTyzTUEJfGRbCTuQIAVR9X5bLdZ1oD7GAuw5kxaq63+H6JHAbigaKwaq9uvr/OXMT4U/2GcWgKfX1oGKXg/g==} '@iarna/toml@2.2.5': resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} - '@noble/hashes@1.5.0': - resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} + '@noble/hashes@1.7.1': + resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} engines: {node: ^14.21.3 || >=16} '@nodelib/fs.scandir@2.1.5': @@ -79,28 +88,76 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@solana/codecs-core@2.0.0-rc.1': - resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==} + '@solana/codecs-core@2.0.0': + resolution: {integrity: sha512-qCG+3hDU5Pm8V6joJjR4j4Zv9md1z0RaecniNDIkEglnxmOUODnmPLWbtOjnDylfItyuZeDihK8hkewdj8cUtw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + + '@solana/codecs-core@2.0.0-rc.4': + resolution: {integrity: sha512-JIrTSps032mSE3wBxW3bXOqWfoy4CMy1CX/XeVCijyh5kLVxZTSDIdRTYdePdL1yzaOZF1Xysvt1DhOUgBdM+A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + + '@solana/codecs-data-structures@2.0.0': + resolution: {integrity: sha512-N98Y4jsrC/XeOgqrfsGqcOFIaOoMsKdAxOmy5oqVaEN67YoGSLNC9ROnqamOAOrsZdicTWx9/YLKFmQi9DPh1A==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-numbers@2.0.0-rc.1': - resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==} + '@solana/codecs-numbers@2.0.0': + resolution: {integrity: sha512-r66i7VzJO1MZkQWZIAI6jjJOFVpnq0+FIabo2Z2ZDtrArFus/SbSEv543yCLeD2tdR/G/p+1+P5On10qF50Y1Q==} + engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5' - '@solana/codecs-strings@2.0.0-rc.1': - resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==} + '@solana/codecs-numbers@2.0.0-rc.4': + resolution: {integrity: sha512-ZJR7TaUO65+3Hzo3YOOUCS0wlzh17IW+j0MZC2LCk1R0woaypRpHKj4iSMYeQOZkMxsd9QT3WNvjFrPC2qA6Sw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + + '@solana/codecs-strings@2.0.0': + resolution: {integrity: sha512-dNqeCypsvaHcjW86H0gYgAZGGkKVBeKVeh7WXlOZ9kno7PeQ2wNkpccyzDfuzaIsKv+HZUD3v/eo86GCvnKazQ==} + engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 typescript: '>=5' - '@solana/errors@2.0.0-rc.1': - resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==} + '@solana/codecs-strings@2.0.0-rc.4': + resolution: {integrity: sha512-LGfK2RL0BKjYYUfzu2FG/gTgCsYOMz9FKVs2ntji6WneZygPxJTV5W98K3J8Rl0JewpCSCFQH3xjLSHBJUS0fA==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5' + + '@solana/codecs@2.0.0': + resolution: {integrity: sha512-xneIG5ppE6WIGaZCK7JTys0uLhzlnEJUdBO8nRVIyerwH6aqCfb0fGe7q5WNNYAVDRSxC0Pc1TDe1hpdx3KWmQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + + '@solana/errors@2.0.0': + resolution: {integrity: sha512-IHlaPFSy4lvYco1oHJ3X8DbchWwAwJaL/4wZKnF1ugwZ0g0re8wbABrqNOe/jyZ84VU9Z14PYM8W9oDAebdJbw==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5' + + '@solana/errors@2.0.0-rc.4': + resolution: {integrity: sha512-0PPaMyB81keEHG/1pnyEuiBVKctbXO641M2w3CIOrYT/wzjunfF0FTxsqq9wYJeYo0AyiefCKGgSPs6wiY2PpQ==} + engines: {node: '>=20.18.0'} hasBin: true peerDependencies: typescript: '>=5' + '@solana/options@2.0.0': + resolution: {integrity: sha512-OVc4KnYosB8oAukQ/htgrxXSxlUP6gUu5Aau6d/BgEkPQzWd/Pr+w91VWw3i3zZuu2SGpedbyh05RoJBe/hSXA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5' + '@types/fs-extra@11.0.4': resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} @@ -129,21 +186,38 @@ packages: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} engines: {node: '>= 0.4'} chalk@5.3.0: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - codama@1.0.0: - resolution: {integrity: sha512-ttJ9n2THpqTD8fP8reec+Y2j4ZTBuonDJk8SiKuS6enZBXd67JF3b+GFKM2S5a0xtxN5Evof5aBlY3JyC+jujQ==} + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + codama@1.2.8: + resolution: {integrity: sha512-0OWQTK4Bx8mgnkudbWoVqhC98iS0py3vNRJHmWVCQ63PSfszgb+DC/9jCkQZMijFQtdUtUcstAYQBHPM5J0exg==} + hasBin: true commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + commander@5.1.0: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} engines: {node: '>= 6'} @@ -160,6 +234,10 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} @@ -167,10 +245,18 @@ packages: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + event-stream@3.3.4: resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} @@ -214,6 +300,14 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -225,6 +319,10 @@ packages: gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -239,6 +337,10 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -265,8 +367,8 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - json-stable-stringify@1.1.1: - resolution: {integrity: sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==} + json-stable-stringify@1.2.1: + resolution: {integrity: sha512-Lp6HbbBgosLmJbjx0pBLbgvx68FaFU1sdkmBuckmhhJ88kL13OA51CDtR2yJB50eCNMH9wRqtQNNiAqQH4YXnA==} engines: {node: '>= 0.4'} jsonfile@6.1.0: @@ -275,9 +377,17 @@ packages: jsonify@0.0.1: resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + map-stream@0.1.0: resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -318,15 +428,22 @@ packages: pause-stream@0.0.11: resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} engines: {node: '>=14'} hasBin: true + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + ps-tree@1.2.0: resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} engines: {node: '>= 0.10'} @@ -346,6 +463,9 @@ packages: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + slash@4.0.0: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} @@ -400,81 +520,128 @@ packages: snapshots: - '@codama/errors@1.0.0': + '@codama/cli@1.0.7(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@codama/node-types': 1.0.0 - chalk: 5.3.0 - commander: 12.1.0 + '@codama/nodes': 1.2.8 + '@codama/nodes-from-anchor': 1.1.8(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/renderers': 1.0.16(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/renderers-js': 1.2.7(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/renderers-js-umi': 1.1.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/renderers-rust': 1.0.16(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/visitors': 1.2.8 + '@codama/visitors-core': 1.2.8 + commander: 13.1.0 + picocolors: 1.1.1 + prompts: 2.4.2 + transitivePeerDependencies: + - chokidar + - fastestsmallesttextencoderdecoder + - typescript - '@codama/node-types@1.0.0': {} + '@codama/errors@1.2.8': + dependencies: + '@codama/node-types': 1.2.8 + chalk: 5.4.1 + commander: 13.1.0 - '@codama/nodes-from-anchor@1.0.0': + '@codama/node-types@1.2.8': {} + + '@codama/nodes-from-anchor@1.1.8(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + '@codama/visitors': 1.2.8 + '@noble/hashes': 1.7.1 + '@solana/codecs': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/nodes@1.2.8': dependencies: - '@codama/errors': 1.0.0 - '@codama/nodes': 1.0.0 - '@codama/visitors': 1.0.0 - '@noble/hashes': 1.5.0 + '@codama/errors': 1.2.8 + '@codama/node-types': 1.2.8 - '@codama/nodes@1.0.0': + '@codama/renderers-core@1.0.10': dependencies: - '@codama/errors': 1.0.0 - '@codama/node-types': 1.0.0 + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + '@codama/visitors-core': 1.2.8 - '@codama/renderers-core@1.0.0': + '@codama/renderers-js-umi@1.1.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@codama/errors': 1.0.0 - '@codama/nodes': 1.0.0 - '@codama/visitors-core': 1.0.0 + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + '@codama/renderers-core': 1.0.10 + '@codama/validators': 1.2.8 + '@codama/visitors-core': 1.2.8 + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + nunjucks: 3.2.4 + prettier: 3.5.3 + transitivePeerDependencies: + - chokidar + - fastestsmallesttextencoderdecoder + - typescript - '@codama/renderers-js@1.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@codama/renderers-js@1.2.7(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@codama/errors': 1.0.0 - '@codama/nodes': 1.0.0 - '@codama/nodes-from-anchor': 1.0.0 - '@codama/renderers-core': 1.0.0 - '@codama/visitors-core': 1.0.0 - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + '@codama/nodes-from-anchor': 1.1.8(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/renderers-core': 1.0.10 + '@codama/visitors-core': 1.2.8 + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) nunjucks: 3.2.4 - prettier: 3.3.3 + prettier: 3.5.3 transitivePeerDependencies: - chokidar - fastestsmallesttextencoderdecoder - typescript - '@codama/renderers-rust@1.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@codama/renderers-rust@1.0.16(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@codama/errors': 1.0.0 - '@codama/nodes': 1.0.0 - '@codama/renderers-core': 1.0.0 - '@codama/visitors-core': 1.0.0 - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + '@codama/renderers-core': 1.0.10 + '@codama/visitors-core': 1.2.8 + '@solana/codecs-strings': 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) nunjucks: 3.2.4 transitivePeerDependencies: - chokidar - fastestsmallesttextencoderdecoder - typescript - '@codama/validators@1.0.0': + '@codama/renderers@1.0.16(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@codama/renderers-js': 1.2.7(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/renderers-js-umi': 1.1.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/renderers-rust': 1.0.16(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + transitivePeerDependencies: + - chokidar + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/validators@1.2.8': dependencies: - '@codama/errors': 1.0.0 - '@codama/nodes': 1.0.0 - '@codama/visitors-core': 1.0.0 + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + '@codama/visitors-core': 1.2.8 - '@codama/visitors-core@1.0.0': + '@codama/visitors-core@1.2.8': dependencies: - '@codama/errors': 1.0.0 - '@codama/nodes': 1.0.0 - json-stable-stringify: 1.1.1 + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + json-stable-stringify: 1.2.1 - '@codama/visitors@1.0.0': + '@codama/visitors@1.2.8': dependencies: - '@codama/errors': 1.0.0 - '@codama/nodes': 1.0.0 - '@codama/visitors-core': 1.0.0 + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + '@codama/visitors-core': 1.2.8 '@iarna/toml@2.2.5': {} - '@noble/hashes@1.5.0': {} + '@noble/hashes@1.7.1': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -488,31 +655,85 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@solana/codecs-core@2.0.0-rc.1(typescript@5.5.3)': + '@solana/codecs-core@2.0.0(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.0.0(typescript@5.5.3) + typescript: 5.5.3 + + '@solana/codecs-core@2.0.0-rc.4(typescript@5.5.3)': + dependencies: + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + typescript: 5.5.3 + + '@solana/codecs-data-structures@2.0.0(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + typescript: 5.5.3 + + '@solana/codecs-numbers@2.0.0(typescript@5.5.3)': dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-numbers@2.0.0-rc.1(typescript@5.5.3)': + '@solana/codecs-numbers@2.0.0-rc.4(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) typescript: 5.5.3 - '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + '@solana/codecs-strings@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.5.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.5.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.5.3) + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.5.3 - '@solana/errors@2.0.0-rc.1(typescript@5.5.3)': + '@solana/codecs-strings@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.5.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.5.3) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.5.3 + + '@solana/codecs@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/options': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@2.0.0(typescript@5.5.3)': dependencies: chalk: 5.3.0 commander: 12.1.0 typescript: 5.5.3 + '@solana/errors@2.0.0-rc.4(typescript@5.5.3)': + dependencies: + chalk: 5.3.0 + commander: 12.1.0 + typescript: 5.5.3 + + '@solana/options@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3)': + dependencies: + '@solana/codecs-core': 2.0.0(typescript@5.5.3) + '@solana/codecs-data-structures': 2.0.0(typescript@5.5.3) + '@solana/codecs-numbers': 2.0.0(typescript@5.5.3) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@solana/errors': 2.0.0(typescript@5.5.3) + typescript: 5.5.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 @@ -540,25 +761,43 @@ snapshots: dependencies: fill-range: 7.0.1 - call-bind@1.0.7: + call-bind-apply-helpers@1.0.2: dependencies: - es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.0 get-intrinsic: 1.2.4 set-function-length: 1.2.2 + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + chalk@5.3.0: {} - codama@1.0.0: + chalk@5.4.1: {} + + codama@1.2.8(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3): dependencies: - '@codama/errors': 1.0.0 - '@codama/nodes': 1.0.0 - '@codama/validators': 1.0.0 - '@codama/visitors': 1.0.0 + '@codama/cli': 1.0.7(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.3) + '@codama/errors': 1.2.8 + '@codama/nodes': 1.2.8 + '@codama/validators': 1.2.8 + '@codama/visitors': 1.2.8 + transitivePeerDependencies: + - chokidar + - fastestsmallesttextencoderdecoder + - typescript commander@12.1.0: {} + commander@13.1.0: {} + commander@5.1.0: {} data-uri-to-buffer@4.0.1: {} @@ -573,14 +812,26 @@ snapshots: dependencies: path-type: 4.0.0 + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + duplexer@0.1.2: {} es-define-property@1.0.0: dependencies: get-intrinsic: 1.2.4 + es-define-property@1.0.1: {} + es-errors@1.3.0: {} + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + event-stream@3.3.4: dependencies: duplexer: 0.1.2 @@ -638,6 +889,24 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -654,6 +923,8 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + gopd@1.2.0: {} + graceful-fs@4.2.11: {} has-property-descriptors@1.0.2: @@ -664,6 +935,8 @@ snapshots: has-symbols@1.0.3: {} + has-symbols@1.1.0: {} + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -682,9 +955,10 @@ snapshots: isexe@2.0.0: {} - json-stable-stringify@1.1.1: + json-stable-stringify@1.2.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 isarray: 2.0.5 jsonify: 0.0.1 object-keys: 1.1.1 @@ -697,8 +971,12 @@ snapshots: jsonify@0.0.1: {} + kleur@3.0.3: {} + map-stream@0.1.0: {} + math-intrinsics@1.1.0: {} + merge2@1.4.1: {} micromatch@4.0.5: @@ -730,9 +1008,16 @@ snapshots: dependencies: through: 2.3.8 + picocolors@1.1.1: {} + picomatch@2.3.1: {} - prettier@3.3.3: {} + prettier@3.5.3: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 ps-tree@1.2.0: dependencies: @@ -755,6 +1040,8 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.2 + sisteransi@1.0.5: {} + slash@4.0.0: {} split@0.3.3: From f3f8f156605d22301999c5d0e72c963469f737c1 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Mon, 3 Mar 2025 15:56:11 +0000 Subject: [PATCH 308/335] Fix "Publish JS Client" workflow (#30) --- .github/workflows/publish-js-client.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/publish-js-client.yml b/.github/workflows/publish-js-client.yml index fcb29c0..d32f29a 100644 --- a/.github/workflows/publish-js-client.yml +++ b/.github/workflows/publish-js-client.yml @@ -38,6 +38,7 @@ jobs: - name: Setup Environment uses: ./.github/actions/setup with: + cargo-cache-key: cargo-programs solana: true - name: Format JS Client @@ -46,6 +47,9 @@ jobs: - name: Lint JS Client run: pnpm clients:js:lint + - name: Build Programs + run: pnpm programs:build + - name: Test JS Client run: pnpm clients:js:test From 7c211e3a4bd6050dcaaae70a300e78c84c6fe255 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Mon, 3 Mar 2025 16:16:06 +0000 Subject: [PATCH 309/335] Bump JS client version manually and fix publish CI (#31) --- .github/workflows/publish-js-client.yml | 2 ++ clients/js/package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-js-client.yml b/.github/workflows/publish-js-client.yml index d32f29a..d6ba832 100644 --- a/.github/workflows/publish-js-client.yml +++ b/.github/workflows/publish-js-client.yml @@ -62,6 +62,8 @@ jobs: steps: - name: Git Checkout uses: actions/checkout@v4 + with: + token: ${{ secrets.ANZA_TEAM_PAT }} - name: Setup Environment uses: ./.github/actions/setup diff --git a/clients/js/package.json b/clients/js/package.json index 854386a..336073f 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,6 +1,6 @@ { "name": "@solana-program/token", - "version": "0.4.1", + "version": "0.5.0", "description": "JavaScript client for the Token program", "sideEffects": false, "module": "./dist/src/index.mjs", From 7433164b2ac60aeb3305016575ec308b0df6555e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:21:19 +0000 Subject: [PATCH 310/335] Publish JS client v0.5.1 --- clients/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/js/package.json b/clients/js/package.json index 336073f..3ad4827 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,6 +1,6 @@ { "name": "@solana-program/token", - "version": "0.5.0", + "version": "0.5.1", "description": "JavaScript client for the Token program", "sideEffects": false, "module": "./dist/src/index.mjs", From f89ab407b2a1157cacfa89fa4f4f31a2585d452a Mon Sep 17 00:00:00 2001 From: Keith Warter Date: Thu, 6 Mar 2025 15:43:07 -0800 Subject: [PATCH 311/335] Update README.md (#33) * Update README.md * Update README.md Co-authored-by: Joe C --------- Co-authored-by: Joe C --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb59148..1749aa1 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ pnpm validator:stop ## Using external programs in your validator -If your program requires any external programs to be running, you'll want to in your local validator. +If your program requires any external programs to be running, you'll want to add them to your local validator. You can do this by adding their program addresses to the `program-dependencies` array in the `Cargo.toml` of your program. From c4689b111789e272600f79e213a3d31bb0ae2f3c Mon Sep 17 00:00:00 2001 From: Jon C Date: Fri, 7 Mar 2025 13:26:27 +0100 Subject: [PATCH 312/335] Audit: Update ring to 0.17.13 (#37) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5bf87d..32e0843 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2133,9 +2133,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.9" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" +checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" dependencies = [ "cc", "cfg-if", From 2f189b15e7bf4ddf57d5011fb475110f0fd31df0 Mon Sep 17 00:00:00 2001 From: Jon C Date: Sat, 8 Mar 2025 01:01:15 +0100 Subject: [PATCH 313/335] CI: Add automated publish job (#34) #### Problem It's time to publish spl-token that uses all of the component crates to make downstream users happy, but there's no publish job on the repo. #### Summary of changes This PR is as bit of a grab-bag of changes, but they're all to make the automated publish job work. The changes contained are: * move semver check job to only run during publish * update publish script to be generic, copying from the libraries repo * update testing script to be generic for rust packages by not running `cargo test-sbf` and instead doing it by hand, like in token-2022 * rename testing script to `test.mjs` * remove `test-sbf` feature from spl-token tests * update solana tools / toolchain versions --- .github/workflows/main.yml | 29 ++--- .github/workflows/publish-rust-client.yml | 122 ------------------- .github/workflows/publish-rust.yml | 140 ++++++++++++++++++++++ Cargo.toml | 11 +- package.json | 6 +- program/tests/assert_instruction_count.rs | 2 - program/tests/close_account.rs | 2 - program/tests/processor.rs | 2 - program/tests/setup.rs | 2 - rust-toolchain.toml | 2 +- scripts/rust/publish.mjs | 35 +++--- scripts/rust/{test-sbf.mjs => test.mjs} | 4 +- 12 files changed, 179 insertions(+), 178 deletions(-) delete mode 100644 .github/workflows/publish-rust-client.yml create mode 100644 .github/workflows/publish-rust.yml rename scripts/rust/{test-sbf.mjs => test.mjs} (56%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1a90eed..52cfd07 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -81,26 +81,6 @@ jobs: - name: Run cargo-audit run: pnpm rust:audit - semver_rust: - name: Check semver Rust - runs-on: ubuntu-latest - steps: - - name: Git Checkout - uses: actions/checkout@v4 - - - name: Setup Environment - uses: ./.github/actions/setup - with: - cargo-cache-key: cargo-semver - - - name: Install cargo-audit - uses: taiki-e/install-action@v2 - with: - tool: cargo-semver-checks - - - name: Run semver checks - run: pnpm rust:semver - spellcheck_rust: name: Spellcheck Rust runs-on: ubuntu-latest @@ -214,7 +194,7 @@ jobs: test_program: name: Test Program runs-on: ubuntu-latest - needs: format_and_lint_program + needs: build_program steps: - name: Git Checkout uses: actions/checkout@v4 @@ -223,7 +203,12 @@ jobs: uses: ./.github/actions/setup with: cargo-cache-key: cargo-test-program - solana: true + + - name: Restore Program Builds + uses: actions/cache/restore@v4 + with: + path: ./**/*.so + key: ${{ runner.os }}-builds-${{ github.sha }} - name: Test run: pnpm programs:test diff --git a/.github/workflows/publish-rust-client.yml b/.github/workflows/publish-rust-client.yml deleted file mode 100644 index ee3f09d..0000000 --- a/.github/workflows/publish-rust-client.yml +++ /dev/null @@ -1,122 +0,0 @@ -name: Publish Rust Client - -on: - workflow_dispatch: - inputs: - level: - description: Level - required: true - default: patch - type: choice - options: - - patch - - minor - - major - - rc - - beta - - alpha - - release - - version - version: - description: Version - required: false - type: string - dry_run: - description: Dry run - required: true - default: true - type: boolean - create_release: - description: Create a GitHub release - required: true - type: boolean - default: true - -jobs: - test_rust: - name: Test Rust client - runs-on: ubuntu-latest - steps: - - name: Git Checkout - uses: actions/checkout@v4 - - - name: Setup Environment - uses: ./.github/actions/setup - with: - cargo-cache-key: cargo-rust-client - clippy: true - rustfmt: true - solana: true - - - name: Format Rust Client - run: pnpm clients:rust:format - - - name: Lint Rust Client - run: pnpm clients:rust:lint - - - name: Test Rust Client - run: pnpm clients:rust:test - - publish_rust: - name: Publish Rust Client - runs-on: ubuntu-latest - needs: test_rust - permissions: - contents: write - steps: - - name: Git Checkout - uses: actions/checkout@v4 - - - name: Setup Environment - uses: ./.github/actions/setup - with: - cargo-cache-key: cargo-publish-rust-client - cargo-cache-fallback-key: cargo-rust-client - clippy: true - rustfmt: true - - - name: Install Cargo Release - run: which cargo-release || cargo install cargo-release - - - name: Ensure CARGO_REGISTRY_TOKEN variable is set - env: - token: ${{ secrets.CARGO_REGISTRY_TOKEN }} - if: ${{ env.token == '' }} - run: | - echo "The CARGO_REGISTRY_TOKEN secret variable is not set" - echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"." - exit 1 - - - name: Set Git Author - run: | - git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - - - name: Publish Rust Client - id: publish - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - run: | - if [ "${{ inputs.level }}" == "version" ]; then - LEVEL=${{ inputs.version }} - else - LEVEL=${{ inputs.level }} - fi - - if [ "${{ inputs.dry_run }}" == "true" ]; then - OPTIONS="--dry-run" - else - OPTIONS="" - fi - - pnpm clients:rust:publish $LEVEL $OPTIONS - - - name: Push Commit and Tag - if: github.event.inputs.dry_run != 'true' - run: git push origin --follow-tags - - - name: Create GitHub release - if: github.event.inputs.create_release == 'true' && github.event.inputs.dry_run != 'true' - uses: ncipollo/release-action@v1 - with: - tag: rust@v${{ steps.publish.outputs.new_version }} diff --git a/.github/workflows/publish-rust.yml b/.github/workflows/publish-rust.yml new file mode 100644 index 0000000..ecbf986 --- /dev/null +++ b/.github/workflows/publish-rust.yml @@ -0,0 +1,140 @@ +name: Publish Rust Crate + +on: + workflow_dispatch: + inputs: + package_path: + description: Path to directory with package to release + required: true + default: 'clients/rust' + type: choice + options: + - clients/rust + - interface + - program + - p-token + level: + description: Level + required: true + default: patch + type: choice + options: + - patch + - minor + - major + dry_run: + description: Dry run + required: true + default: true + type: boolean + create_release: + description: Create a GitHub release + required: true + type: boolean + default: true + +jobs: + test: + name: Test Rust Crate + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + clippy: true + rustfmt: true + solana: true + cargo-cache-key: cargo-test-publish-${{ inputs.package_path }} + cargo-cache-fallback-key: cargo-test-publish + + - name: Install cargo-audit + uses: taiki-e/install-action@v2 + with: + tool: cargo-semver-checks + + - name: Format + run: pnpm zx ./scripts/rust/format.mjs "${{ inputs.package_path }}" + + - name: Lint + run: pnpm zx ./scripts/rust/lint.mjs "${{ inputs.package_path }}" + + - name: Build programs + run: pnpm programs:build + + - name: Test + run: pnpm zx ./scripts/rust/test.mjs "${{ inputs.package_path }}" + + - name: Check semver + run: pnpm rust:semver ${{ inputs.package_path }} --release-type ${{ inputs.level }} + + publish: + name: Publish Rust Crate + runs-on: ubuntu-latest + needs: test + permissions: + contents: write + steps: + - name: Git Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.ANZA_TEAM_PAT }} + fetch-depth: 0 # get the whole history for git-cliff + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-publish-${{ inputs.package_path }} + cargo-cache-fallback-key: cargo-publish + + - name: Install Cargo Release + run: which cargo-release || cargo install cargo-release + + - name: Ensure CARGO_REGISTRY_TOKEN variable is set + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + if: ${{ env.CARGO_REGISTRY_TOKEN == '' }} + run: | + echo "The CARGO_REGISTRY_TOKEN secret variable is not set" + echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"." + exit 1 + + - name: Set Git Author + run: | + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + - name: Publish Crate + id: publish + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: | + if [ "${{ inputs.dry_run }}" == "true" ]; then + OPTIONS="--dry-run" + else + OPTIONS="" + fi + + pnpm rust:publish "${{ inputs.package_path }}" "${{ inputs.level }}" $OPTIONS + + - name: Generate a changelog + if: github.event.inputs.create_release == 'true' + uses: orhun/git-cliff-action@v3 + with: + config: "scripts/cliff.toml" + args: | + "${{ steps.publish.outputs.old_git_tag }}"..main + --include-path "${{ inputs.package_path }}/**" + --github-repo "${{ github.repository }}" + env: + OUTPUT: TEMP_CHANGELOG.md + GITHUB_REPO: ${{ github.repository }} + + - name: Create GitHub release + if: github.event.inputs.create_release == 'true' && github.event.inputs.dry_run != 'true' + uses: ncipollo/release-action@v1 + with: + tag: ${{ steps.publish.outputs.new_git_tag }} + bodyFile: TEMP_CHANGELOG.md diff --git a/Cargo.toml b/Cargo.toml index ec0aeab..e18e299 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,13 +10,18 @@ check-cfg = [ ] [workspace.metadata.cli] -solana = "2.1.0" +solana = "2.2.0" # Specify Rust toolchains for rustfmt, clippy, and build. # Any unprovided toolchains default to stable. [workspace.metadata.toolchains] -format = "nightly-2024-08-08" -lint = "nightly-2024-08-08" +format = "nightly-2024-11-22" +lint = "nightly-2024-11-22" [workspace.metadata.spellcheck] config = "scripts/spellcheck.toml" + +[workspace.metadata.release] +pre-release-commit-message = "Publish {{crate_name}} v{{version}}" +tag-message = "Publish {{crate_name}} v{{version}}" +consolidate-commits = false diff --git a/package.json b/package.json index 412f6a8..07c04bf 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "programs:build": "zx ./scripts/rust/build-sbf.mjs program", "programs:format": "zx ./scripts/rust/format.mjs program", "programs:lint": "zx ./scripts/rust/lint.mjs program", - "programs:test": "zx ./scripts/rust/test-sbf.mjs program", + "programs:test": "zx ./scripts/rust/test.mjs program", "solana:check": "zx ./scripts/check-solana-version.mjs", "solana:link": "zx ./scripts/link-solana-version.mjs", "generate": "pnpm generate:clients", @@ -18,11 +18,11 @@ "clients:js:test": "zx ./scripts/js/test.mjs", "clients:rust:format": "zx ./scripts/rust/format.mjs clients/rust", "clients:rust:lint": "zx ./scripts/rust/lint.mjs clients/rust", - "clients:rust:publish": "zx ./scripts/rust/publish.mjs clients/rust", - "clients:rust:test": "zx ./scripts/rust/test-sbf.mjs clients/rust", + "clients:rust:test": "zx ./scripts/rust/test.mjs clients/rust", "template:upgrade": "zx ./scripts/upgrade-template.mjs", "rust:spellcheck": "cargo spellcheck --code 1", "rust:audit": "zx ./scripts/rust/audit.mjs", + "rust:publish": "zx ./scripts/rust/publish.mjs", "rust:semver": "cargo semver-checks" }, "devDependencies": { diff --git a/program/tests/assert_instruction_count.rs b/program/tests/assert_instruction_count.rs index 0143a11..0fda122 100644 --- a/program/tests/assert_instruction_count.rs +++ b/program/tests/assert_instruction_count.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use { diff --git a/program/tests/close_account.rs b/program/tests/close_account.rs index cb1ac55..17f0354 100644 --- a/program/tests/close_account.rs +++ b/program/tests/close_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use { diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 3e8ad71..025577a 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - //! Program state processor tests use { diff --git a/program/tests/setup.rs b/program/tests/setup.rs index 4365dea..0067724 100644 --- a/program/tests/setup.rs +++ b/program/tests/setup.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - use { solana_sdk::{ account::Account as SolanaAccount, program_pack::Pack, pubkey::Pubkey, rent::Rent, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 1de01fa..fcb78ec 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.81.0" +channel = "1.84.1" diff --git a/scripts/rust/publish.mjs b/scripts/rust/publish.mjs index b7a9fa6..28bd91b 100644 --- a/scripts/rust/publish.mjs +++ b/scripts/rust/publish.mjs @@ -3,18 +3,25 @@ import 'zx/globals'; import { cliArguments, getCargo, workingDirectory } from '../utils.mjs'; const dryRun = argv['dry-run'] ?? false; -const [level] = cliArguments(); +const [folder, level] = cliArguments(); +if (!folder) { + throw new Error('A path to a directory with a Rust package — e.g. "clients/cli" — must be provided.'); +} if (!level) { - throw new Error('A version level — e.g. "path" — must be provided.'); + throw new Error('A version level — e.g. "patch" — must be provided.'); } -// Go to the client directory and install the dependencies. -cd(path.join(workingDirectory, 'clients', 'rust')); +cd(path.join(workingDirectory, folder)); + +const packageToml = getCargo(folder).package; +const oldVersion = packageToml.version; +const packageName = packageToml.name; +const tagName = path.basename(folder); -// Publish the new version. +// Publish the new version, commit the repo change, tag it, and push it all. const releaseArgs = dryRun ? [] - : ['--no-push', '--no-tag', '--no-confirm', '--execute']; + : ['--tag-name', `${tagName}@v{{version}}`, '--no-confirm', '--execute']; await $`cargo release ${level} ${releaseArgs}`; // Stop here if this is a dry run. @@ -23,18 +30,12 @@ if (dryRun) { } // Get the new version. -const newVersion = getCargo(path.join('clients', 'rust')).package.version; +const newVersion = getCargo(folder).package.version; +const newGitTag = `${tagName}@v${newVersion}`; +const oldGitTag = `${tagName}@v${oldVersion}`; // Expose the new version to CI if needed. if (process.env.CI) { - await $`echo "new_version=${newVersion}" >> $GITHUB_OUTPUT`; + await $`echo "new_git_tag=${newGitTag}" >> $GITHUB_OUTPUT`; + await $`echo "old_git_tag=${oldGitTag}" >> $GITHUB_OUTPUT`; } - -// Soft reset the last commit so we can create our own commit and tag. -await $`git reset --soft HEAD~1`; - -// Commit the new version. -await $`git commit -am "Publish Rust client v${newVersion}"`; - -// Tag the new version. -await $`git tag -a rust@v${newVersion} -m "Rust client v${newVersion}"`; diff --git a/scripts/rust/test-sbf.mjs b/scripts/rust/test.mjs similarity index 56% rename from scripts/rust/test-sbf.mjs rename to scripts/rust/test.mjs index 1c11835..6142f0b 100644 --- a/scripts/rust/test-sbf.mjs +++ b/scripts/rust/test.mjs @@ -3,6 +3,6 @@ import 'zx/globals'; import { cliArguments, workingDirectory } from '../utils.mjs'; const [folder, ...args] = cliArguments(); +const sbfOutDir = path.join(workingDirectory, 'target', 'deploy'); const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml'); - -await $`RUST_LOG=error cargo test-sbf --manifest-path ${manifestPath} ${args}`; +await $`RUST_LOG=error SBF_OUT_DIR=${sbfOutDir} cargo test --manifest-path ${manifestPath} ${args}`; From 5adaa0e6878fb97b1ff2d6a647a7407832475bbe Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Mon, 10 Mar 2025 13:49:32 +0000 Subject: [PATCH 314/335] p-token: Add interface and p-token to workspace (#24) * Update workspace * Remove unused * Filter p-token program * Rename interface crate * Add readme * Nits * Update cargo lock --- Cargo.lock | 3281 ++++++++++++++++- Cargo.toml | 8 +- interface/Cargo.toml | 15 +- interface/README.md | 25 + p-token/Cargo.toml | 24 +- p-token/README.md | 15 + p-token/keypair.json | 1 - p-token/src/processor/amount_to_ui_amount.rs | 2 +- p-token/src/processor/close_account.rs | 2 +- .../src/processor/get_account_data_size.rs | 2 +- .../processor/initialize_immutable_owner.rs | 2 +- p-token/src/processor/initialize_mint.rs | 2 +- p-token/src/processor/mod.rs | 2 +- p-token/src/processor/revoke.rs | 2 +- p-token/src/processor/set_authority.rs | 2 +- p-token/src/processor/shared/approve.rs | 2 +- p-token/src/processor/shared/burn.rs | 2 +- .../processor/shared/initialize_account.rs | 2 +- .../processor/shared/initialize_multisig.rs | 2 +- p-token/src/processor/shared/mint_to.rs | 2 +- .../processor/shared/toggle_account_state.rs | 2 +- p-token/src/processor/shared/transfer.rs | 2 +- p-token/src/processor/sync_native.rs | 2 +- p-token/src/processor/ui_amount_to_amount.rs | 2 +- p-token/tests/initialize_mint.rs | 2 +- p-token/tests/initialize_mint2.rs | 2 +- p-token/tests/setup/mint.rs | 2 +- p-token/tests/setup/mod.rs | 2 +- program/Cargo.toml | 8 +- scripts/utils.mjs | 7 +- 30 files changed, 3305 insertions(+), 121 deletions(-) create mode 100644 interface/README.md delete mode 100644 p-token/keypair.json diff --git a/Cargo.lock b/Cargo.lock index 32e0843..c75292c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -17,6 +17,58 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "agave-transaction-view" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4778fd549144e8776fb7ac04e7dac598546f0d4cb0b25e336cb0a7d93120ddb9" +dependencies = [ + "solana-hash", + "solana-message", + "solana-packet", + "solana-pubkey", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-svm-transaction", +] + [[package]] name = "ahash" version = "0.8.11" @@ -54,6 +106,41 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "aquamarine" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f50776554130342de4836ba542aa85a4ddb361690d7e8df13774d7284c3d5c2" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "ark-bn254" version = "0.4.0" @@ -189,6 +276,62 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + [[package]] name = "async-compression" version = "0.4.18" @@ -203,13 +346,35 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.4.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -241,6 +406,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.21.7" @@ -292,6 +463,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + [[package]] name = "blake3" version = "1.5.5" @@ -470,15 +650,53 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror 1.0.69", +] + [[package]] name = "cc" version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" dependencies = [ + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -508,7 +726,32 @@ version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "chrono-humanize" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" +dependencies = [ + "chrono", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", ] [[package]] @@ -524,6 +767,38 @@ dependencies = [ "unreachable", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -593,6 +868,25 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -612,6 +906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] @@ -625,11 +920,20 @@ dependencies = [ "subtle", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", "digest 0.9.0", @@ -702,6 +1006,49 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", + "rayon", +] + +[[package]] +name = "data-encoding" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f" + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint 0.4.6", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivation-path" version = "0.2.0" @@ -719,6 +1066,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.9.0" @@ -739,6 +1092,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "dir-diff" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" +dependencies = [ + "walkdir", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -751,18 +1113,47 @@ dependencies = [ ] [[package]] -name = "eager" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" - -[[package]] -name = "ed25519" -version = "1.5.3" +name = "dlopen2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" dependencies = [ - "signature", + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", ] [[package]] @@ -771,7 +1162,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek 3.2.1", + "curve25519-dalek 3.2.0", "ed25519", "rand 0.7.3", "serde", @@ -791,12 +1182,30 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "educe" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -826,6 +1235,19 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "enum-ordinalize" +version = "3.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -855,6 +1277,33 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener 5.4.0", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -873,6 +1322,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "five8_const" version = "0.1.3" @@ -898,6 +1359,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -928,6 +1398,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "futures" version = "0.3.31" @@ -976,6 +1452,17 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -988,6 +1475,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" @@ -997,6 +1490,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1051,12 +1545,44 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "governor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" +dependencies = [ + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", +] + [[package]] name = "h2" version = "0.3.26" @@ -1072,7 +1598,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.13", "tracing", ] @@ -1094,12 +1620,24 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1109,6 +1647,18 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "histogram" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" + [[package]] name = "hmac" version = "0.8.1" @@ -1212,11 +1762,34 @@ dependencies = [ "futures-util", "http", "hyper", - "rustls", + "rustls 0.21.12", "tokio", "tokio-rustls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "1.5.0" @@ -1362,16 +1935,79 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "rayon", + "serde", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "index_list" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa38453685e5fe724fd23ff6c1a158c1e2ca21ce0c2718fa11e96e70e99fd4de" + [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", ] +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1402,6 +2038,35 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine 4.6.7", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -1412,6 +2077,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "keccak" version = "0.1.5" @@ -1433,6 +2113,17 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.8.0", + "libc", + "redox_syscall", +] + [[package]] name = "libsecp256k1" version = "0.6.0" @@ -1499,6 +2190,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" + [[package]] name = "litemap" version = "0.7.4" @@ -1521,6 +2218,25 @@ version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +[[package]] +name = "lz4" +version = "1.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" +dependencies = [ + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.11.1+lz4-1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1545,6 +2261,18 @@ dependencies = [ "autocfg", ] +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "mime" version = "0.3.17" @@ -1552,12 +2280,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "miniz_oxide" -version = "0.8.4" +name = "mime_guess" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ - "adler2", + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" +dependencies = [ + "adler2", ] [[package]] @@ -1571,6 +2315,54 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "mockall" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "mollusk-svm" version = "0.1.0" @@ -1631,6 +2423,47 @@ dependencies = [ "solana-transaction-context", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.8.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "num" version = "0.2.1" @@ -1676,6 +2509,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.4.2" @@ -1728,6 +2567,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + [[package]] name = "num_enum" version = "0.7.3" @@ -1749,6 +2598,12 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.36.7" @@ -1758,6 +2613,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.20.2" @@ -1796,6 +2660,12 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "openssl-sys" version = "0.9.105" @@ -1808,6 +2678,31 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "js-sys", + "lazy_static", + "percent-encoding", + "pin-project", + "rand 0.8.5", + "thiserror 1.0.69", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1846,6 +2741,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1861,6 +2765,26 @@ dependencies = [ "num", ] +[[package]] +name = "pin-project" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1873,12 +2797,82 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pinocchio" +version = "0.7.1" +source = "git+https://github.com/febo/pinocchio.git?branch=febo%2Fclose-unstable#246a026bb74c501ba83ea18201000e56c097cb0d" + +[[package]] +name = "pinocchio-log" +version = "0.3.0" +source = "git+https://github.com/febo/pinocchio.git?branch=febo%2Fclose-unstable#246a026bb74c501ba83ea18201000e56c097cb0d" +dependencies = [ + "pinocchio-log-macro", +] + +[[package]] +name = "pinocchio-log-macro" +version = "0.3.0" +source = "git+https://github.com/febo/pinocchio.git?branch=febo%2Fclose-unstable#246a026bb74c501ba83ea18201000e56c097cb0d" +dependencies = [ + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "pinocchio-pubkey" +version = "0.2.2" +source = "git+https://github.com/febo/pinocchio.git?branch=febo%2Fclose-unstable#246a026bb74c501ba83ea18201000e56c097cb0d" +dependencies = [ + "five8_const", + "pinocchio", +] + +[[package]] +name = "pinocchio-token-program" +version = "0.0.0" +dependencies = [ + "assert_matches", + "pinocchio", + "pinocchio-log", + "solana-program-test", + "solana-sdk", + "spl-token 4.0.2", + "spl-token-interface", + "test-case", +] + [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1888,6 +2882,36 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "predicates" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools 0.10.5", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" + +[[package]] +name = "predicates-tree" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -1906,6 +2930,27 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", +] + [[package]] name = "proc-macro2" version = "1.0.93" @@ -1955,12 +3000,80 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "quanta" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.22", + "socket2", + "thiserror 2.0.11", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom 0.2.15", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.23.22", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror 2.0.11", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.38" @@ -2051,17 +3164,55 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.5.8" +name = "rand_xoshiro" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "bitflags 2.8.0", + "rand_core 0.6.4", ] [[package]] -name = "regex" -version = "1.11.1" +name = "raw-cpuid" +version = "11.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6928fa44c097620b706542d428957635951bade7143269085389d42c8a4927e" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "regex" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ @@ -2109,11 +3260,12 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -2121,16 +3273,31 @@ dependencies = [ "system-configuration", "tokio", "tokio-rustls", - "tokio-util", + "tokio-util 0.7.13", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg", ] +[[package]] +name = "reqwest-middleware" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "task-local-extensions", + "thiserror 1.0.69", +] + [[package]] name = "ring" version = "0.17.13" @@ -2151,6 +3318,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2160,6 +3333,15 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "0.38.43" @@ -2169,7 +3351,20 @@ dependencies = [ "bitflags 2.8.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" +dependencies = [ + "bitflags 2.8.0", + "errno", + "libc", + "linux-raw-sys 0.9.2", "windows-sys 0.59.0", ] @@ -2181,10 +3376,37 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -2194,6 +3416,51 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c7dc240fec5517e6c4eab3310438636cfe6391dfc345ba013109909a90d136" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.22", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.8", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -2204,6 +3471,17 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.19" @@ -2228,6 +3506,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scc" version = "2.3.0" @@ -2237,6 +3524,15 @@ dependencies = [ "sdd", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2259,11 +3555,44 @@ version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.8.0", + "core-foundation", + "core-foundation-sys", + "libc", + "num-bigint 0.4.6", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" -version = "1.0.24" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "seqlock" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" +dependencies = [ + "parking_lot", +] [[package]] name = "serde" @@ -2375,6 +3704,17 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.9.9" @@ -2409,12 +3749,30 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "1.6.4" @@ -2427,6 +3785,16 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + [[package]] name = "slab" version = "0.4.9" @@ -2470,6 +3838,22 @@ dependencies = [ "solana-sysvar", ] +[[package]] +name = "solana-account-decoder-client-types" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad44260b45eb8c75005fbe361186136e52e2cf0de2139f530295f04f9521ad" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-pubkey", + "zstd", +] + [[package]] name = "solana-account-info" version = "2.2.1" @@ -2483,6 +3867,55 @@ dependencies = [ "solana-pubkey", ] +[[package]] +name = "solana-accounts-db" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7c93e9f9184f8c785da2136e84adb4123e45297890ec1d39baa2f693bc83c3" +dependencies = [ + "ahash", + "bincode", + "blake3", + "bv", + "bytemuck", + "bytemuck_derive", + "bzip2", + "crossbeam-channel", + "dashmap", + "index_list", + "indexmap", + "itertools 0.12.1", + "lazy_static", + "log", + "lz4", + "memmap2", + "modular-bitfield", + "num_cpus", + "num_enum", + "rand 0.8.5", + "rayon", + "seqlock", + "serde", + "serde_derive", + "smallvec", + "solana-bucket-map", + "solana-clock", + "solana-hash", + "solana-inline-spl", + "solana-lattice-hash", + "solana-measure", + "solana-metrics", + "solana-nohash-hasher", + "solana-pubkey", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-svm-transaction", + "static_assertions", + "tar", + "tempfile", + "thiserror 2.0.11", +] + [[package]] name = "solana-address-lookup-table-interface" version = "2.2.2" @@ -2500,6 +3933,31 @@ dependencies = [ "solana-slot-hashes", ] +[[package]] +name = "solana-address-lookup-table-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffd21cefb44a61a051f5f36bdb8863b619754e057099506a73cabd8716b10d4" +dependencies = [ + "bincode", + "bytemuck", + "log", + "num-derive", + "num-traits", + "solana-address-lookup-table-interface", + "solana-bincode", + "solana-clock", + "solana-feature-set", + "solana-instruction", + "solana-log-collector", + "solana-packet", + "solana-program-runtime", + "solana-pubkey", + "solana-system-interface", + "solana-transaction-context", + "thiserror 2.0.11", +] + [[package]] name = "solana-atomic-u64" version = "2.2.1" @@ -2510,19 +3968,70 @@ dependencies = [ ] [[package]] -name = "solana-big-mod-exp" -version = "2.2.1" +name = "solana-banks-client" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +checksum = "57b8593f50e34f44ed168dccbac0a9b8e43e138ac75102dac6635fbdfff88d1e" dependencies = [ - "num-bigint 0.4.6", - "num-traits", - "solana-define-syscall", + "borsh 1.5.5", + "futures", + "solana-banks-interface", + "solana-program", + "solana-sdk", + "tarpc", + "thiserror 2.0.11", + "tokio", + "tokio-serde", ] [[package]] -name = "solana-bincode" -version = "2.2.1" +name = "solana-banks-interface" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414f5d83bf9aa83d5a387959d0849bd4a3df86f8b09219278f964688710faeb4" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk", + "tarpc", +] + +[[package]] +name = "solana-banks-server" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f3a1c619d54d4a8c30802b4ac6f572a293914e592f2c3e904be3cdacbb22333" +dependencies = [ + "bincode", + "crossbeam-channel", + "futures", + "solana-banks-interface", + "solana-client", + "solana-feature-set", + "solana-runtime", + "solana-runtime-transaction", + "solana-sdk", + "solana-send-transaction-service", + "solana-svm", + "tarpc", + "tokio", + "tokio-serde", +] + +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-bincode" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" dependencies = [ @@ -2593,6 +4102,7 @@ dependencies = [ "solana-instruction", "solana-keccak-hasher", "solana-loader-v3-interface", + "solana-loader-v4-interface", "solana-log-collector", "solana-measure", "solana-packet", @@ -2616,6 +4126,117 @@ dependencies = [ "thiserror 2.0.11", ] +[[package]] +name = "solana-bucket-map" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf96e6e1d0f3a66be62587ff675c7feaa630f827c2e1514ecf4ea48940436a9" +dependencies = [ + "bv", + "bytemuck", + "bytemuck_derive", + "log", + "memmap2", + "modular-bitfield", + "num_enum", + "rand 0.8.5", + "solana-clock", + "solana-measure", + "solana-pubkey", + "tempfile", +] + +[[package]] +name = "solana-builtins" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586a702f2d78f6d9cba627c63757deb9e7944cc0531e689100bd71473618f16" +dependencies = [ + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-config-program", + "solana-feature-set", + "solana-loader-v4-program", + "solana-program-runtime", + "solana-pubkey", + "solana-sdk-ids", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", + "solana-zk-elgamal-proof-program", + "solana-zk-token-proof-program", +] + +[[package]] +name = "solana-builtins-default-costs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aff717901cb7ed2ae65a69994d2e758b0468e84d460e60a793a0c862a2c254bc" +dependencies = [ + "ahash", + "lazy_static", + "log", + "qualifier_attr", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-config-program", + "solana-feature-set", + "solana-loader-v4-program", + "solana-pubkey", + "solana-sdk-ids", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", +] + +[[package]] +name = "solana-client" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c77e1bdc6d727070a3ddfb571cfaf4a8e46a4d81049fd8510c7fe12a40b4768" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap", + "indicatif", + "log", + "quinn", + "rayon", + "solana-account", + "solana-client-traits", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-measure", + "solana-message", + "solana-pubkey", + "solana-pubsub-client", + "solana-quic-client", + "solana-quic-definitions", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", + "solana-signature", + "solana-signer", + "solana-streamer", + "solana-thin-client", + "solana-time-utils", + "solana-tpu-client", + "solana-transaction", + "solana-transaction-error", + "solana-udp-client", + "thiserror 2.0.11", + "tokio", +] + [[package]] name = "solana-client-traits" version = "2.2.1" @@ -2681,6 +4302,27 @@ dependencies = [ "solana-program-entrypoint", ] +[[package]] +name = "solana-compute-budget-instruction" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66d536fe93ff372340151b053d003f9d2a0d695c65fd28c11224f629a5e1da7" +dependencies = [ + "log", + "solana-borsh", + "solana-builtins-default-costs", + "solana-compute-budget", + "solana-compute-budget-interface", + "solana-feature-set", + "solana-instruction", + "solana-packet", + "solana-pubkey", + "solana-sdk-ids", + "solana-svm-transaction", + "solana-transaction-error", + "thiserror 2.0.11", +] + [[package]] name = "solana-compute-budget-interface" version = "2.2.1" @@ -2694,6 +4336,93 @@ dependencies = [ "solana-sdk-ids", ] +[[package]] +name = "solana-compute-budget-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd0daef640520980f40b578367dd4ca1181e592b36b4959c04f13a617701ac6" +dependencies = [ + "qualifier_attr", + "solana-program-runtime", +] + +[[package]] +name = "solana-config-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f6a00ecb0eb3e4c68186a26216deb6c2376929f235fc9f3fd59e5745df937a" +dependencies = [ + "bincode", + "chrono", + "serde", + "serde_derive", + "solana-account", + "solana-bincode", + "solana-instruction", + "solana-log-collector", + "solana-packet", + "solana-program-runtime", + "solana-pubkey", + "solana-sdk-ids", + "solana-short-vec", + "solana-stake-interface", + "solana-system-interface", + "solana-transaction-context", +] + +[[package]] +name = "solana-connection-cache" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc19eff90b17e022a5642b7ab0d3fe5c8dc251cb9d2b032dc73bd25fa4171e" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap", + "log", + "rand 0.8.5", + "rayon", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-time-utils", + "solana-transaction-error", + "thiserror 2.0.11", + "tokio", +] + +[[package]] +name = "solana-cost-model" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fa9756128d456489956fc3b105d0ba6d5434e00200303103c13b1587f3ffc0c" +dependencies = [ + "ahash", + "lazy_static", + "log", + "solana-bincode", + "solana-borsh", + "solana-builtins-default-costs", + "solana-clock", + "solana-compute-budget", + "solana-compute-budget-instruction", + "solana-compute-budget-interface", + "solana-feature-set", + "solana-fee-structure", + "solana-metrics", + "solana-packet", + "solana-pubkey", + "solana-runtime-transaction", + "solana-sdk-ids", + "solana-svm-transaction", + "solana-system-interface", + "solana-transaction-error", + "solana-vote-program", +] + [[package]] name = "solana-cpi" version = "2.2.1" @@ -2865,6 +4594,17 @@ dependencies = [ "solana-sha256-hasher", ] +[[package]] +name = "solana-fee" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7af7739e65896d4ac160230949dce021c9ee8c1ce26cb13bebbec01cd9c95" +dependencies = [ + "solana-feature-set", + "solana-fee-structure", + "solana-svm-transaction", +] + [[package]] name = "solana-fee-calculator" version = "2.2.1" @@ -2957,6 +4697,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "solana-inline-spl" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f623a26022a600a64fc233412808d79c5a135952eee643c127c4b42aa089b8aa" +dependencies = [ + "bytemuck", + "solana-pubkey", +] + [[package]] name = "solana-instruction" version = "2.2.1" @@ -3036,6 +4786,18 @@ dependencies = [ "solana-sysvar-id", ] +[[package]] +name = "solana-lattice-hash" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "450482255f6951d21bb4b8987a794b0da751b492108e74567f945ccde809039d" +dependencies = [ + "base64 0.22.1", + "blake3", + "bs58", + "bytemuck", +] + [[package]] name = "solana-loader-v2-interface" version = "2.2.1" @@ -3080,6 +4842,32 @@ dependencies = [ "solana-system-interface", ] +[[package]] +name = "solana-loader-v4-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "885258f9506b74d0bd72aea1b8c0492e2f28af625fba914b07cd7ca892d38465" +dependencies = [ + "log", + "qualifier_attr", + "solana-account", + "solana-bincode", + "solana-bpf-loader-program", + "solana-compute-budget", + "solana-instruction", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-log-collector", + "solana-measure", + "solana-packet", + "solana-program-runtime", + "solana-pubkey", + "solana-sbpf", + "solana-sdk-ids", + "solana-transaction-context", + "solana-type-overrides", +] + [[package]] name = "solana-log-collector" version = "2.2.0" @@ -3163,10 +4951,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33e9de00960197412e4be3902a6cd35e60817c511137aca6c34c66cd5d4017ec" [[package]] -name = "solana-nonce" -version = "2.2.1" +name = "solana-net-utils" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +checksum = "797b3c3534d999e868e5859392976619653b3bc679e7e729019b462c775bb498" +dependencies = [ + "anyhow", + "bincode", + "bytes", + "crossbeam-channel", + "itertools 0.12.1", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-serde", + "tokio", + "url", +] + +[[package]] +name = "solana-nohash-hasher" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" + +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" dependencies = [ "serde", "serde_derive", @@ -3218,6 +5034,38 @@ dependencies = [ "serde_with", ] +[[package]] +name = "solana-perf" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "682214ffa84ad08fe3a3a013fc0a487596b007027777fa7d7f865d8dcd3d808c" +dependencies = [ + "ahash", + "bincode", + "bv", + "caps", + "curve25519-dalek 4.1.3", + "dlopen2", + "fnv", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "serde", + "solana-hash", + "solana-message", + "solana-metrics", + "solana-packet", + "solana-pubkey", + "solana-rayon-threadlimit", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-time-utils", +] + [[package]] name = "solana-poh-config" version = "2.2.1" @@ -3452,6 +5300,43 @@ dependencies = [ "thiserror 2.0.11", ] +[[package]] +name = "solana-program-test" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6e241cf9090db4dde586e37607b849ab69db2bc3045855966214fa19cd3ace" +dependencies = [ + "assert_matches", + "async-trait", + "base64 0.22.1", + "bincode", + "chrono-humanize", + "crossbeam-channel", + "log", + "serde", + "solana-accounts-db", + "solana-banks-client", + "solana-banks-interface", + "solana-banks-server", + "solana-bpf-loader-program", + "solana-compute-budget", + "solana-feature-set", + "solana-inline-spl", + "solana-instruction", + "solana-log-collector", + "solana-logger", + "solana-program-runtime", + "solana-runtime", + "solana-sbpf", + "solana-sdk", + "solana-sdk-ids", + "solana-svm", + "solana-timings", + "solana-vote-program", + "thiserror 2.0.11", + "tokio", +] + [[package]] name = "solana-pubkey" version = "2.2.1" @@ -3479,6 +5364,64 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "solana-pubsub-client" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "181d082f1fc71e3e72b4e8e1226bbfbd844d9aa053c18a5d44acf3ca3f4ce6b1" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock", + "solana-pubkey", + "solana-rpc-client-api", + "solana-signature", + "thiserror 2.0.11", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ddb60775a36033662bbf70957403deba846b45783d4a5b16cdadcc11ff878a" +dependencies = [ + "async-lock", + "async-trait", + "futures", + "itertools 0.12.1", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.22", + "solana-connection-cache", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-pubkey", + "solana-quic-definitions", + "solana-rpc-client-api", + "solana-signer", + "solana-streamer", + "solana-tls-utils", + "solana-transaction-error", + "thiserror 2.0.11", + "tokio", +] + [[package]] name = "solana-quic-definitions" version = "2.2.1" @@ -3488,6 +5431,16 @@ dependencies = [ "solana-keypair", ] +[[package]] +name = "solana-rayon-threadlimit" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca12616e0d5a20708797e7e57dcf1912451efd1059d64c8d9660f2e8552817c" +dependencies = [ + "lazy_static", + "num_cpus", +] + [[package]] name = "solana-rent" version = "2.2.1" @@ -3550,6 +5503,199 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "solana-rpc-client" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039ad5152d72bd530ecc98dc55fa36d7e16ce92b2faf58befc07d51da1b72cdb" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode", + "bs58", + "indicatif", + "log", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-clock", + "solana-commitment-config", + "solana-epoch-info", + "solana-epoch-schedule", + "solana-feature-gate-interface", + "solana-hash", + "solana-instruction", + "solana-message", + "solana-pubkey", + "solana-rpc-client-api", + "solana-signature", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80ce7f8565fc928d04ae56d69423b514c2e41566b48e828b868355c7034de4b7" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bs58", + "jsonrpc-core", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-clock", + "solana-commitment-config", + "solana-fee-calculator", + "solana-inflation", + "solana-inline-spl", + "solana-pubkey", + "solana-signer", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a3adc401074f5ecd7101d48ba4b66e0698d4e41879de4bb75162f521a5233d" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-hash", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-rpc-client", + "solana-sdk-ids", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-runtime" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acc5805ea88f4020c7899229d507cc3a8ca0e3afc512db173f8ec70104183d2c" +dependencies = [ + "ahash", + "aquamarine", + "arrayref", + "base64 0.22.1", + "bincode", + "blake3", + "bv", + "bytemuck", + "bzip2", + "crossbeam-channel", + "dashmap", + "dir-diff", + "flate2", + "fnv", + "im", + "index_list", + "itertools 0.12.1", + "lazy_static", + "libc", + "log", + "lz4", + "memmap2", + "mockall", + "modular-bitfield", + "num-derive", + "num-traits", + "num_cpus", + "num_enum", + "percentage", + "qualifier_attr", + "rand 0.8.5", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "serde_with", + "solana-accounts-db", + "solana-bpf-loader-program", + "solana-bucket-map", + "solana-builtins", + "solana-compute-budget", + "solana-compute-budget-instruction", + "solana-config-program", + "solana-cost-model", + "solana-feature-set", + "solana-fee", + "solana-inline-spl", + "solana-lattice-hash", + "solana-measure", + "solana-metrics", + "solana-nohash-hasher", + "solana-nonce-account", + "solana-perf", + "solana-program", + "solana-program-runtime", + "solana-pubkey", + "solana-rayon-threadlimit", + "solana-runtime-transaction", + "solana-sdk", + "solana-stake-program", + "solana-svm", + "solana-svm-rent-collector", + "solana-svm-transaction", + "solana-timings", + "solana-transaction-status-client-types", + "solana-unified-scheduler-logic", + "solana-version", + "solana-vote", + "solana-vote-program", + "static_assertions", + "strum", + "strum_macros", + "symlink", + "tar", + "tempfile", + "thiserror 2.0.11", + "zstd", +] + +[[package]] +name = "solana-runtime-transaction" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c37fec5b3d291b382a6b21aac6df461da8cc2d733b3d095596129a78d72f7" +dependencies = [ + "agave-transaction-view", + "log", + "solana-compute-budget", + "solana-compute-budget-instruction", + "solana-hash", + "solana-message", + "solana-pubkey", + "solana-sdk-ids", + "solana-signature", + "solana-svm-transaction", + "solana-transaction", + "solana-transaction-error", + "thiserror 2.0.11", +] + [[package]] name = "solana-sanitize" version = "2.2.1" @@ -3563,7 +5709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66a3ce7a0f4d6830124ceb2c263c36d1ee39444ec70146eb49b939e557e72b96" dependencies = [ "byteorder", - "combine", + "combine 3.8.1", "hash32", "libc", "log", @@ -3729,6 +5875,25 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "solana-send-transaction-service" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd59874c1f709fffa4b455c524e9bd98e419ce7df0aa6a37826989fed4c06271" +dependencies = [ + "crossbeam-channel", + "itertools 0.12.1", + "log", + "solana-client", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-runtime", + "solana-sdk", + "solana-tpu-client", + "tokio", +] + [[package]] name = "solana-serde" version = "2.2.1" @@ -3873,10 +6038,154 @@ dependencies = [ ] [[package]] -name = "solana-system-interface" -version = "1.0.0" +name = "solana-stake-program" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" +checksum = "7045076ed29255f228dede3a2554755449a610e42f3694afadb59e3424920858" +dependencies = [ + "bincode", + "log", + "solana-account", + "solana-bincode", + "solana-clock", + "solana-config-program", + "solana-feature-set", + "solana-genesis-config", + "solana-instruction", + "solana-log-collector", + "solana-native-token", + "solana-packet", + "solana-program-runtime", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-stake-interface", + "solana-sysvar", + "solana-transaction-context", + "solana-type-overrides", + "solana-vote-interface", +] + +[[package]] +name = "solana-streamer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41e73688c30ff6016b74c4b609fc78bad08f2b2a3b53006cbc331933e7e86aa" +dependencies = [ + "async-channel", + "bytes", + "crossbeam-channel", + "dashmap", + "futures", + "futures-util", + "governor", + "histogram", + "indexmap", + "itertools 0.12.1", + "libc", + "log", + "nix", + "pem", + "percentage", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.22", + "smallvec", + "socket2", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-packet", + "solana-perf", + "solana-pubkey", + "solana-quic-definitions", + "solana-signature", + "solana-signer", + "solana-time-utils", + "solana-tls-utils", + "solana-transaction-error", + "solana-transaction-metrics-tracker", + "thiserror 2.0.11", + "tokio", + "tokio-util 0.7.13", + "x509-parser", +] + +[[package]] +name = "solana-svm" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e74fc2cd71d75f3e311bb568604184b51e90c280040efabaa3ab3c8a2c4d85" +dependencies = [ + "ahash", + "itertools 0.12.1", + "log", + "percentage", + "serde", + "serde_derive", + "solana-account", + "solana-bpf-loader-program", + "solana-clock", + "solana-compute-budget", + "solana-compute-budget-instruction", + "solana-feature-set", + "solana-fee-structure", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-loader-v4-program", + "solana-log-collector", + "solana-measure", + "solana-message", + "solana-nonce", + "solana-nonce-account", + "solana-precompiles", + "solana-program", + "solana-program-runtime", + "solana-pubkey", + "solana-rent", + "solana-rent-debits", + "solana-sdk", + "solana-sdk-ids", + "solana-svm-rent-collector", + "solana-svm-transaction", + "solana-timings", + "solana-transaction-context", + "solana-transaction-error", + "solana-type-overrides", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-svm-rent-collector" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4387d97a27730ef97b52b81f814e3e31f869f001ede75fb53f2fcbc335c03e" +dependencies = [ + "solana-sdk", +] + +[[package]] +name = "solana-svm-transaction" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ffa8d1463d6813433cd4f31ec1c96abc85dc693f29b80986a77186dfe5e144" +dependencies = [ + "solana-hash", + "solana-message", + "solana-pubkey", + "solana-sdk-ids", + "solana-signature", + "solana-transaction", +] + +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" dependencies = [ "js-sys", "num-traits", @@ -3976,6 +6285,35 @@ dependencies = [ "solana-sdk-ids", ] +[[package]] +name = "solana-thin-client" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c6b2376c3e0a6ae5538d86818e403841b8b11861c6b39a943221c6c2164eea" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-account", + "solana-client-traits", + "solana-clock", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction", + "solana-transaction-error", +] + [[package]] name = "solana-time-utils" version = "2.2.1" @@ -3993,6 +6331,53 @@ dependencies = [ "solana-pubkey", ] +[[package]] +name = "solana-tls-utils" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9da625758b52894dfde5d72f3b78f5141045ec5296a5acadec934dd2ccbb1b" +dependencies = [ + "rustls 0.23.22", + "solana-keypair", + "solana-pubkey", + "solana-signer", + "x509-parser", +] + +[[package]] +name = "solana-tpu-client" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1045fd558ad215e8d2f2a0e87154444ea0dc8821a80f088dcdcf4831a510879a" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap", + "indicatif", + "log", + "rayon", + "solana-client-traits", + "solana-clock", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-measure", + "solana-message", + "solana-net-utils", + "solana-pubkey", + "solana-pubsub-client", + "solana-quic-definitions", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature", + "solana-signer", + "solana-transaction", + "solana-transaction-error", + "thiserror 2.0.11", + "tokio", +] + [[package]] name = "solana-transaction" version = "2.2.1" @@ -4049,6 +6434,46 @@ dependencies = [ "solana-sanitize", ] +[[package]] +name = "solana-transaction-metrics-tracker" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d97bffaf9515adbf3b1a04efbc9dbc815d635da684f358357e76abdbe2a4e5" +dependencies = [ + "base64 0.22.1", + "bincode", + "lazy_static", + "log", + "rand 0.8.5", + "solana-packet", + "solana-perf", + "solana-short-vec", + "solana-signature", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6d348cd4cd79cab56e58590a301aef5b5247ba503f94f97900db3a0f8f7ff94" +dependencies = [ + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-commitment-config", + "solana-message", + "solana-reward-info", + "solana-signature", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "thiserror 2.0.11", +] + [[package]] name = "solana-type-overrides" version = "2.2.0" @@ -4059,17 +6484,85 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "solana-udp-client" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5859430b42c8f6412d57230b2918a1cc89597cbc26b546e84fbc5277538898" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-keypair", + "solana-net-utils", + "solana-streamer", + "solana-transaction-error", + "thiserror 2.0.11", + "tokio", +] + +[[package]] +name = "solana-unified-scheduler-logic" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73db72aa7dfb35bc8715cd9990a68671e4d970fff63080c45fc44fed59f54946" +dependencies = [ + "assert_matches", + "solana-pubkey", + "solana-runtime-transaction", + "solana-transaction", + "static_assertions", +] + [[package]] name = "solana-validator-exit" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bbf6d7a3c0b28dd5335c52c0e9eae49d0ae489a8f324917faf0ded65a812c1d" +[[package]] +name = "solana-version" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a843098ea779826eb0fb4b04c8aee3acb42ecc1f9595a9e40306e3938026d3" +dependencies = [ + "semver", + "serde", + "serde_derive", + "solana-feature-set", + "solana-sanitize", + "solana-serde-varint", +] + +[[package]] +name = "solana-vote" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b1735371e033fd6c340ea8a6dfcf8992a6c05c6bf428955100697c8f8baab3e" +dependencies = [ + "itertools 0.12.1", + "log", + "serde", + "serde_derive", + "solana-account", + "solana-bincode", + "solana-clock", + "solana-hash", + "solana-instruction", + "solana-packet", + "solana-pubkey", + "solana-sdk-ids", + "solana-signature", + "solana-svm-transaction", + "solana-transaction", + "solana-vote-interface", + "thiserror 2.0.11", +] + [[package]] name = "solana-vote-interface" -version = "2.2.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e9f6a1651310a94cd5a1a6b7f33ade01d9e5ea38a2220becb5fd737b756514" +checksum = "d4507bb9d071fb81cfcf676f12fba3db4098f764524ef0b5567d671a81d41f3e" dependencies = [ "bincode", "num-derive", @@ -4089,6 +6582,169 @@ dependencies = [ "solana-system-interface", ] +[[package]] +name = "solana-vote-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4862f099c25d20857d270a2423ed4e0dd11038ad2f7f25905ff72c33c5132828" +dependencies = [ + "bincode", + "log", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-account", + "solana-bincode", + "solana-clock", + "solana-epoch-schedule", + "solana-feature-set", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-packet", + "solana-program-runtime", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-signer", + "solana-slot-hashes", + "solana-transaction", + "solana-transaction-context", + "solana-vote-interface", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-zk-elgamal-proof-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75248110af0908a5280adca0f8b1f7fc8b7299358a7476cfcac4ebd039bd5921" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-instruction", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk-ids", + "solana-zk-sdk", +] + +[[package]] +name = "solana-zk-sdk" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f66acae4f01a718825ae0201ea0a05ae3c9a3afb27a7eed6f0803b96da639b" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "js-sys", + "lazy_static", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.11", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "solana-zk-token-proof-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7deadf45ab349e02ccd402f9534b7ae9ebbb7a70160f5068a09a71946be103cb" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-feature-set", + "solana-instruction", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk-ids", + "solana-zk-token-sdk", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77367202d84b62d224289ff7174ddecd737626108e5a3278deb1c3b38d050084" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "lazy_static", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-curve25519", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.11", + "zeroize", +] + +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spl-token" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9e171cbcb4b1f72f6d78ed1e975cb467f56825c27d09b8dd2608e4e7fc8b3b" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + [[package]] name = "spl-token" version = "7.0.0" @@ -4122,24 +6778,66 @@ dependencies = [ "thiserror 2.0.11", ] +[[package]] +name = "spl-token-interface" +version = "0.0.0" +dependencies = [ + "pinocchio", + "pinocchio-pubkey", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -4168,6 +6866,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + [[package]] name = "synstructure" version = "0.13.1" @@ -4183,34 +6893,89 @@ dependencies = [ name = "system-configuration" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tar" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tarpc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38a012bed6fb9681d3bf71ffaa4f88f3b4b9ed3198cda6e4c8462d24d4bb80" +dependencies = [ + "anyhow", + "fnv", + "futures", + "humantime", + "opentelemetry", + "pin-project", + "rand 0.8.5", + "serde", + "static_assertions", + "tarpc-plugins", + "thiserror 1.0.69", + "tokio", + "tokio-serde", + "tokio-util 0.6.10", + "tracing", + "tracing-opentelemetry", +] + +[[package]] +name = "tarpc-plugins" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "system-configuration-sys" -version = "0.5.0" +name = "task-local-extensions" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" dependencies = [ - "core-foundation-sys", - "libc", + "pin-utils", ] [[package]] name = "tempfile" -version = "3.15.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" dependencies = [ "cfg-if", "fastrand", - "getrandom 0.2.15", + "getrandom 0.3.1", "once_cell", - "rustix", + "rustix 1.0.1", "windows-sys 0.59.0", ] @@ -4223,6 +6988,45 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "test-case" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-core" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "test-case-macros" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "test-case-core", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -4263,6 +7067,47 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -4298,18 +7143,89 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "windows-sys 0.52.0", ] +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "tokio-rustls" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-serde" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" +dependencies = [ + "bincode", + "bytes", + "educe", + "futures-core", + "futures-sink", + "pin-project", + "serde", + "serde_json", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots 0.25.4", +] + +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "slab", "tokio", ] @@ -4364,10 +7280,23 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ + "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "tracing-core" version = "0.1.33" @@ -4375,6 +7304,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-opentelemetry" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" +dependencies = [ + "once_cell", + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", ] [[package]] @@ -4383,6 +7337,27 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.21.12", + "sha1", + "thiserror 1.0.69", + "url", + "utf-8", + "webpki-roots 0.24.0", +] + [[package]] name = "typenum" version = "1.17.0" @@ -4395,12 +7370,40 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unreachable" version = "1.0.0" @@ -4437,6 +7440,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf16_iter" version = "1.0.5" @@ -4449,6 +7458,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" @@ -4476,6 +7491,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -4497,6 +7522,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -4578,6 +7612,34 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09aed61f5e8d2c18344b3faa33a4c837855fe56642757754775548fee21386c4" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki 0.101.7", +] + [[package]] name = "webpki-roots" version = "0.25.4" @@ -4615,6 +7677,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -4782,6 +7853,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -4794,6 +7874,35 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs", + "base64 0.13.1", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "xattr" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" +dependencies = [ + "libc", + "linux-raw-sys 0.4.15", + "rustix 0.38.43", +] + [[package]] name = "yoke" version = "0.7.5" @@ -4815,7 +7924,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.96", - "synstructure", + "synstructure 0.13.1", ] [[package]] @@ -4857,14 +7966,14 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.96", - "synstructure", + "synstructure 0.13.1", ] [[package]] name = "zeroize" -version = "1.3.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -4901,3 +8010,31 @@ dependencies = [ "quote", "syn 2.0.96", ] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index e18e299..940ada8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,12 @@ [workspace] resolver = "2" -members = ["program"] +members = ["interface", "p-token", "program"] + +[workspace.package] +authors = ["Anza Maintainers "] +repository = "https://github.com/solana-program/token" +license = "Apache-2.0" +edition = "2021" [workspace.lints.rust.unexpected_cfgs] level = "warn" diff --git a/interface/Cargo.toml b/interface/Cargo.toml index ab63d2e..2e3ae9e 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -1,15 +1,16 @@ [package] -name = "token-interface" +name = "spl-token-interface" version = "0.0.0" -edition = { workspace = true } +description = "Instructions and types for interacting with SPL Token program" +authors = { workspace = true} +repository = { workspace = true} +license = { workspace = true} +edition = { workspace = true} readme = "./README.md" -license = { workspace = true } -repository = { workspace = true } -publish = false [lib] crate-type = ["rlib"] [dependencies] -pinocchio = { workspace = true } -pinocchio-pubkey = { workspace = true } +pinocchio = { version = "0.7", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } +pinocchio-pubkey = { version = "0.2", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } diff --git a/interface/README.md b/interface/README.md new file mode 100644 index 0000000..c3444c6 --- /dev/null +++ b/interface/README.md @@ -0,0 +1,25 @@ +

+ + Solana + +

+ +# SPL Token Interface + +This crate contains instructions and constructors for interacting with the [SPL Token program](https://spl.solana.com/token). + +The Token program defines a common implementation for Fungible and Non Fungible tokens. + +## Getting Started + +From your project folder: + +```bash +cargo add spl-token-interface +``` + +This will add the `spl-token-interface` dependency to your `Cargo.toml` file. + +## Documentation + +Read more about the SPL Token program on the crate [documentation](https://docs.rs/spl-token-interface). \ No newline at end of file diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index d527968..63dfb31 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -1,14 +1,12 @@ [package] -name = "token-program" +name = "pinocchio-token-program" version = "0.0.0" -edition = { workspace = true } +description = "A pinocchio-based Token (aka 'p-token') program" +authors = { workspace = true} +repository = { workspace = true} +license = { workspace = true} +edition = { workspace = true} readme = "./README.md" -license = { workspace = true } -repository = { workspace = true } -publish = false - -[package.metadata.solana] -program-id = "PToken1111111111111111111111111111111111111" [lib] crate-type = ["cdylib"] @@ -18,13 +16,13 @@ logging = [] test-sbf = [] [dependencies] -pinocchio = { workspace = true } -pinocchio-log = { workspace = true } -token-interface = { version = "^0", path = "../interface" } +pinocchio = { version = "0.7", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } +pinocchio-log = { version = "0.3", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } +spl-token-interface = { version = "^0", path = "../interface" } [dev-dependencies] assert_matches = "1.5.0" -solana-program-test = "~1.18" -solana-sdk = "~1.18" +solana-program-test = "2.1" +solana-sdk = "2.1" spl-token = { version="^4", features=["no-entrypoint"] } test-case = "3.3.1" diff --git a/p-token/README.md b/p-token/README.md index 4fa737c..f2c4f51 100644 --- a/p-token/README.md +++ b/p-token/README.md @@ -1,3 +1,18 @@ # `p-token` A `pinocchio`-based Token program. + +## Overview + +`p-token` is a reimplementation of the SPL Token program, one of the most popular programs on Solana, using [`pinocchio`](https://github.com/anza-xyz/pinocchio). The purpose is to have an implementation that optimizes the compute units, while being fully compatible with the original implementation — i.e., support the exact same instruction and account layouts as SPL Token, byte for byte. + +## Features + +- `no_std` crate +- Same instruction and account layout as SPL Token +- Minimal CU usage + + +## License + +The code is licensed under the [Apache License Version 2.0](LICENSE) diff --git a/p-token/keypair.json b/p-token/keypair.json deleted file mode 100644 index 3092538..0000000 --- a/p-token/keypair.json +++ /dev/null @@ -1 +0,0 @@ -[178,215,114,55,146,0,60,153,90,63,112,26,148,148,111,230,196,181,5,124,14,237,142,43,207,114,102,60,145,103,53,23,249,192,123,198,160,247,138,44,243,38,29,240,233,86,143,132,170,26,154,207,174,195,147,223,12,231,253,195,118,55,207,100] \ No newline at end of file diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 6c13993..b90fcf8 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -3,7 +3,7 @@ use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; use pinocchio_log::logger::{Argument, Logger}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{load, mint::Mint}, }; diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs index 3f90dea..618b567 100644 --- a/p-token/src/processor/close_account.rs +++ b/p-token/src/processor/close_account.rs @@ -1,7 +1,7 @@ use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load}, }; diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index 0131b48..b789317 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -1,7 +1,7 @@ use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load, mint::Mint, RawType}, }; diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs index ba98c28..7a59336 100644 --- a/p-token/src/processor/initialize_immutable_owner.rs +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -1,5 +1,5 @@ use pinocchio::{account_info::AccountInfo, msg, program_error::ProgramError, ProgramResult}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load_unchecked, Initializable}, }; diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index ee52eb4..935acfd 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -6,7 +6,7 @@ use pinocchio::{ sysvars::{rent::Rent, Sysvar}, ProgramResult, }; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{load_mut_unchecked, mint::Mint, Initializable}, }; diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 0f0592f..ee807d4 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -8,7 +8,7 @@ use pinocchio::{ account_info::AccountInfo, memory::sol_memcpy, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use token_interface::{ +use spl_token_interface::{ error::TokenError, program::ID as TOKEN_PROGRAM_ID, state::{ diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs index 50b01dd..936b73a 100644 --- a/p-token/src/processor/revoke.rs +++ b/p-token/src/processor/revoke.rs @@ -1,5 +1,5 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load_mut}, }; diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index fcfa9f1..5da19c2 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use token_interface::{ +use spl_token_interface::{ error::TokenError, instruction::AuthorityType, state::{account::Account, load_mut, mint::Mint, RawType}, diff --git a/p-token/src/processor/shared/approve.rs b/p-token/src/processor/shared/approve.rs index d5e90d5..22bae66 100644 --- a/p-token/src/processor/shared/approve.rs +++ b/p-token/src/processor/shared/approve.rs @@ -1,5 +1,5 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load, load_mut, mint::Mint}, }; diff --git a/p-token/src/processor/shared/burn.rs b/p-token/src/processor/shared/burn.rs index 06f741a..cae712e 100644 --- a/p-token/src/processor/shared/burn.rs +++ b/p-token/src/processor/shared/burn.rs @@ -1,5 +1,5 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load_mut, mint::Mint}, }; diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index 796e82e..02fcacd 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -5,7 +5,7 @@ use pinocchio::{ sysvars::{rent::Rent, Sysvar}, ProgramResult, }; -use token_interface::{ +use spl_token_interface::{ error::TokenError, native_mint::is_native_mint, state::{ diff --git a/p-token/src/processor/shared/initialize_multisig.rs b/p-token/src/processor/shared/initialize_multisig.rs index 0d45fa8..fc863fb 100644 --- a/p-token/src/processor/shared/initialize_multisig.rs +++ b/p-token/src/processor/shared/initialize_multisig.rs @@ -4,7 +4,7 @@ use pinocchio::{ sysvars::{rent::Rent, Sysvar}, ProgramResult, }; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{load_mut_unchecked, multisig::Multisig, Initializable}, }; diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs index 773039f..3548cc4 100644 --- a/p-token/src/processor/shared/mint_to.rs +++ b/p-token/src/processor/shared/mint_to.rs @@ -1,5 +1,5 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load_mut, mint::Mint}, }; diff --git a/p-token/src/processor/shared/toggle_account_state.rs b/p-token/src/processor/shared/toggle_account_state.rs index c9ff11a..ba1b7aa 100644 --- a/p-token/src/processor/shared/toggle_account_state.rs +++ b/p-token/src/processor/shared/toggle_account_state.rs @@ -1,5 +1,5 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, account_state::AccountState, load, load_mut, mint::Mint}, }; diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index c71a5af..84ae7cf 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -1,5 +1,5 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load, load_mut, load_mut_unchecked, mint::Mint}, }; diff --git a/p-token/src/processor/sync_native.rs b/p-token/src/processor/sync_native.rs index 4ccc276..8507e59 100644 --- a/p-token/src/processor/sync_native.rs +++ b/p-token/src/processor/sync_native.rs @@ -1,5 +1,5 @@ use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{account::Account, load_mut}, }; diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index 823ffbc..b4c5b2e 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -2,7 +2,7 @@ use core::str::from_utf8; use pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, }; -use token_interface::{ +use spl_token_interface::{ error::TokenError, state::{load, mint::Mint}, }; diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 175e805..e94b57f 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -14,7 +14,7 @@ use solana_sdk::{ system_instruction, transaction::Transaction, }; -use token_interface::state::mint::Mint; +use spl_token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index 683e1e3..b0d7fa1 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -14,7 +14,7 @@ use solana_sdk::{ system_instruction, transaction::Transaction, }; -use token_interface::state::mint::Mint; +use spl_token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/setup/mint.rs b/p-token/tests/setup/mint.rs index 2714757..dd8ceec 100644 --- a/p-token/tests/setup/mint.rs +++ b/p-token/tests/setup/mint.rs @@ -5,7 +5,7 @@ use solana_sdk::{ program_error::ProgramError, pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, transaction::Transaction, }; -use token_interface::state::mint::Mint; +use spl_token_interface::state::mint::Mint; pub async fn initialize( context: &mut ProgramTestContext, diff --git a/p-token/tests/setup/mod.rs b/p-token/tests/setup/mod.rs index e79b8ce..c607de2 100644 --- a/p-token/tests/setup/mod.rs +++ b/p-token/tests/setup/mod.rs @@ -5,4 +5,4 @@ pub mod account; #[allow(dead_code)] pub mod mint; -pub const TOKEN_PROGRAM_ID: Pubkey = Pubkey::new_from_array(token_interface::program::ID); +pub const TOKEN_PROGRAM_ID: Pubkey = Pubkey::new_from_array(spl_token_interface::program::ID); diff --git a/program/Cargo.toml b/program/Cargo.toml index 8971f63..3b5e041 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -2,10 +2,10 @@ name = "spl-token" version = "7.0.0" description = "Solana Program Library Token" -authors = ["Anza Maintainers "] -repository = "https://github.com/solana-program/token" -license = "Apache-2.0" -edition = "2021" +authors = { workspace = true} +repository = { workspace = true} +license = { workspace = true} +edition = { workspace = true} [features] no-entrypoint = [] diff --git a/scripts/utils.mjs b/scripts/utils.mjs index 44ee564..aebe5d5 100644 --- a/scripts/utils.mjs +++ b/scripts/utils.mjs @@ -65,8 +65,11 @@ export function getProgramFolders() { } export function getAllProgramFolders() { - return getCargo().workspace.members.filter((member) => - (getCargo(member).lib?.['crate-type'] ?? []).includes('cdylib') + return getCargo().workspace.members.filter( + (member) => + (getCargo(member).lib?.['crate-type'] ?? []).includes('cdylib') && + // Exclude the pinocchio-token-program crate. + getCargo(member).package?.name !== 'pinocchio-token-program' ); } From 52ee7f2f49ee535b472838e33281388e22075057 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Mon, 10 Mar 2025 13:57:57 +0000 Subject: [PATCH 315/335] interface: Fix spelling (#25) * Update workspace * Remove unused * Filter p-token program * Rename interface crate * Add readme * Nits * Update cargo lock * Update workspace * Fix spelling * More spelling fixes * Update cargo lock --- interface/src/instruction.rs | 58 ++++++++++++++++------------------ interface/src/native_mint.rs | 2 +- interface/src/state/account.rs | 2 +- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index a829e9a..f928cc3 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -36,7 +36,7 @@ pub enum TokenInstruction<'a> { /// associated with another mint, that mint must be initialized before this /// command can succeed. /// - /// The `InitializeAccount` instruction requires no signers and MUST be + /// The [`InitializeAccount`] instruction requires no signers and MUST be /// included within the same Transaction as the system program's /// `CreateAccount` instruction that creates the account being initialized. /// Otherwise another party can acquire ownership of the uninitialized @@ -57,7 +57,7 @@ pub enum TokenInstruction<'a> { /// present. The variant field represents the number of signers (M) /// required to validate this multisignature account. /// - /// The `InitializeMultisig` instruction requires no signers and MUST be + /// The [`InitializeMultisig`] instruction requires no signers and MUST be /// included within the same Transaction as the system program's /// `CreateAccount` instruction that creates the account being initialized. /// Otherwise another party can acquire ownership of the uninitialized @@ -67,8 +67,7 @@ pub enum TokenInstruction<'a> { /// /// 0. `[writable]` The multisignature account to initialize. /// 1. `[]` Rent sysvar - /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <= - /// 11. + /// 2. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <= 11`. InitializeMultisig { /// The number of signers (M) required to validate this multisignature /// account. @@ -91,7 +90,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The source account. /// 1. `[writable]` The destination account. /// 2. `[]` The source account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. `..+M` `[signer]` M signer accounts. Transfer { /// The amount of tokens to transfer. amount: u64, @@ -111,7 +110,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The source account. /// 1. `[]` The delegate. /// 2. `[]` The source account's multisignature owner. - /// 3. ..3+M `[signer]` M signer accounts + /// 3. `..+M` `[signer]` M signer accounts Approve { /// The amount of tokens the delegate is approved for. amount: u64, @@ -128,7 +127,7 @@ pub enum TokenInstruction<'a> { /// * Multisignature owner /// 0. `[writable]` The source account. /// 1. `[]` The source account's multisignature owner. - /// 2. ..2+M `[signer]` M signer accounts + /// 2. `..+M` `[signer]` M signer accounts Revoke, /// Sets a new authority of a mint or account. @@ -142,7 +141,7 @@ pub enum TokenInstruction<'a> { /// * Multisignature authority /// 0. `[writable]` The mint or account to change the authority of. /// 1. `[]` The mint's or account's current multisignature authority. - /// 2. ..2+M `[signer]` M signer accounts + /// 2. `..+M` `[signer]` M signer accounts SetAuthority { /// The type of authority to update. authority_type: AuthorityType, @@ -164,7 +163,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The mint. /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. `..+M` `[signer]` M signer accounts. MintTo { /// The amount of new tokens to mint. amount: u64, @@ -184,7 +183,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to burn from. /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. `..+M` `[signer]` M signer accounts. Burn { /// The amount of tokens to burn. amount: u64, @@ -204,10 +203,10 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to close. /// 1. `[writable]` The destination account. /// 2. `[]` The account's multisignature owner. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. `..+M` `[signer]` M signer accounts. CloseAccount, - /// Freeze an Initialized account using the Mint's freeze_authority (if + /// Freeze an Initialized account using the Mint's [`freeze_authority`] (if /// set). /// /// Accounts expected by this instruction: @@ -221,10 +220,10 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to freeze. /// 1. `[]` The token mint. /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. `..+M` `[signer]` M signer accounts. FreezeAccount, - /// Thaw a Frozen account using the Mint's freeze_authority (if set). + /// Thaw a Frozen account using the Mint's [`freeze_authority`] (if set). /// /// Accounts expected by this instruction: /// @@ -237,7 +236,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to freeze. /// 1. `[]` The token mint. /// 2. `[]` The mint's multisignature freeze authority. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. `..+M` `[signer]` M signer accounts. ThawAccount, /// Transfers tokens from one account to another either directly or via a @@ -262,7 +261,7 @@ pub enum TokenInstruction<'a> { /// 1. `[]` The token mint. /// 2. `[writable]` The destination account. /// 3. `[]` The source account's multisignature owner/delegate. - /// 4. ..4+M `[signer]` M signer accounts. + /// 4. `..+M` `[signer]` M signer accounts. TransferChecked { /// The amount of tokens to transfer. amount: u64, @@ -290,7 +289,7 @@ pub enum TokenInstruction<'a> { /// 1. `[]` The token mint. /// 2. `[]` The delegate. /// 3. `[]` The source account's multisignature owner. - /// 4. ..4+M `[signer]` M signer accounts + /// 4. `..+M` `[signer]` M signer accounts ApproveChecked { /// The amount of tokens the delegate is approved for. amount: u64, @@ -301,7 +300,7 @@ pub enum TokenInstruction<'a> { /// Mints new tokens to an account. The native mint does not support /// minting. /// - /// This instruction differs from MintTo in that the decimals value is + /// This instruction differs from [`MintTo`] in that the decimals value is /// checked by the caller. This may be useful when creating transactions /// offline or within a hardware wallet. /// @@ -316,7 +315,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The mint. /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. `..+M` `[signer]` M signer accounts. MintToChecked { /// The amount of new tokens to mint. amount: u64, @@ -324,7 +323,7 @@ pub enum TokenInstruction<'a> { decimals: u8, }, - /// Burns tokens by removing them from an account. `BurnChecked` does not + /// Burns tokens by removing them from an account. [`BurnChecked`] does not /// support accounts associated with the native mint, use `CloseAccount` /// instead. /// @@ -343,7 +342,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to burn from. /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. - /// 3. ..3+M `[signer]` M signer accounts. + /// 3. `..+M` `[signer]` M signer accounts. BurnChecked { /// The amount of tokens to burn. amount: u64, @@ -351,7 +350,7 @@ pub enum TokenInstruction<'a> { decimals: u8, }, - /// Like InitializeAccount, but the owner pubkey is passed via instruction + /// Like [`InitializeAccount`], but the owner pubkey is passed via instruction /// data rather than the accounts list. This variant may be preferable /// when using Cross Program Invocation from an instruction that does /// not need the owner's `AccountInfo` otherwise. @@ -378,7 +377,7 @@ pub enum TokenInstruction<'a> { /// lamports. SyncNative, - /// Like InitializeAccount2, but does not require the Rent sysvar to be + /// Like [`InitializeAccount2`], but does not require the Rent sysvar to be /// provided /// /// Accounts expected by this instruction: @@ -390,14 +389,13 @@ pub enum TokenInstruction<'a> { owner: Pubkey, }, - /// Like InitializeMultisig, but does not require the Rent sysvar to be + /// Like [`InitializeMultisig`], but does not require the Rent sysvar to be /// provided /// /// Accounts expected by this instruction: /// /// 0. `[writable]` The multisignature account to initialize. - /// 1. ..1+N. `[]` The signer accounts, must equal to N where 1 <= N <= - /// 11. + /// 1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <= 11`. InitializeMultisig2 { /// The number of signers (M) required to validate this multisignature /// account. @@ -433,7 +431,7 @@ pub enum TokenInstruction<'a> { /// Initialize the Immutable Owner extension for the given token account /// /// Fails if the account has already been initialized, so must be called - /// before `InitializeAccount`. + /// before [`InitializeAccount`]. /// /// No-ops in this version of the program, but is included for compatibility /// with the Associated Token Account program. @@ -446,7 +444,7 @@ pub enum TokenInstruction<'a> { /// None InitializeImmutableOwner, - /// Convert an Amount of tokens to a UiAmount `string`, using the given + /// Convert an Amount of tokens to a `UiAmount` `string`, using the given /// mint. In this version of the program, the mint can only specify the /// number of decimals. /// @@ -463,7 +461,7 @@ pub enum TokenInstruction<'a> { amount: u64, }, - /// Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using + /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount, using /// the given mint. In this version of the program, the mint can only /// specify the number of decimals. /// @@ -474,7 +472,7 @@ pub enum TokenInstruction<'a> { /// /// 0. `[]` The mint to calculate for UiAmountToAmount { - /// The ui_amount of tokens to reformat. + /// The `ui_amount` of tokens to reformat. ui_amount: &'a str, }, // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the diff --git a/interface/src/native_mint.rs b/interface/src/native_mint.rs index a99a5bc..f0a0d73 100644 --- a/interface/src/native_mint.rs +++ b/interface/src/native_mint.rs @@ -2,7 +2,7 @@ use pinocchio::pubkey::Pubkey; -/// There are 10^9 lamports in one SOL +/// There are `10^9` lamports in one SOL pub const DECIMALS: u8 = 9; // The Mint for native SOL Token accounts diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index 0f0ba64..a4cf6d3 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -31,7 +31,7 @@ pub struct Account { /// Indicates whether this account represents a native token or not. is_native: [u8; 4], - /// If is_native.is_some, this is a native token, and the value logs the + /// If `is_native.is_some`, this is a native token, and the value logs the /// rent-exempt reserve. An Account is required to be rent-exempt, so /// the value is used by the Processor to ensure that wrapped SOL /// accounts do not drop below this threshold. From 08540e264e3a38f0bdc8ed8f385d3c51c22f3f58 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Mon, 10 Mar 2025 14:24:32 +0000 Subject: [PATCH 316/335] p-token: Add scripts (#27) * Update workspace * Rename interface crate * Add readme * Update cargo lock * Update workspace * Fix spelling * Fix clippy warning * Fix p-token binary name * Add p-token scripts --- interface/README.md | 2 +- p-token/tests/amount_to_ui_amount.rs | 2 +- p-token/tests/approve.rs | 2 +- p-token/tests/approve_checked.rs | 2 +- p-token/tests/burn.rs | 2 +- p-token/tests/burn_checked.rs | 2 +- p-token/tests/close_account.rs | 2 +- p-token/tests/freeze_account.rs | 2 +- p-token/tests/initialize_account.rs | 2 +- p-token/tests/initialize_account2.rs | 2 +- p-token/tests/initialize_account3.rs | 2 +- p-token/tests/initialize_mint.rs | 2 +- p-token/tests/initialize_mint2.rs | 2 +- p-token/tests/initialize_multisig.rs | 2 +- p-token/tests/initialize_multisig2.rs | 2 +- p-token/tests/mint_to.rs | 2 +- p-token/tests/mint_to_checked.rs | 2 +- p-token/tests/revoke.rs | 2 +- p-token/tests/set_authority.rs | 2 +- p-token/tests/thaw_account.rs | 2 +- p-token/tests/transfer.rs | 2 +- p-token/tests/transfer_checked.rs | 2 +- p-token/tests/ui_amount_to_amount.rs | 2 +- package.json | 4 +++- 24 files changed, 26 insertions(+), 24 deletions(-) diff --git a/interface/README.md b/interface/README.md index c3444c6..5300eed 100644 --- a/interface/README.md +++ b/interface/README.md @@ -22,4 +22,4 @@ This will add the `spl-token-interface` dependency to your `Cargo.toml` file. ## Documentation -Read more about the SPL Token program on the crate [documentation](https://docs.rs/spl-token-interface). \ No newline at end of file +Read more about the SPL Token interface on the crate [documentation](https://docs.rs/spl-token-interface). diff --git a/p-token/tests/amount_to_ui_amount.rs b/p-token/tests/amount_to_ui_amount.rs index 402be08..b9d7079 100644 --- a/p-token/tests/amount_to_ui_amount.rs +++ b/p-token/tests/amount_to_ui_amount.rs @@ -9,7 +9,7 @@ use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn amount_to_ui_amount(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/approve.rs b/p-token/tests/approve.rs index f3b28e2..b47baa7 100644 --- a/p-token/tests/approve.rs +++ b/p-token/tests/approve.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn approve(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs index e34fa7a..43c4837 100644 --- a/p-token/tests/approve_checked.rs +++ b/p-token/tests/approve_checked.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn approve_checked(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/burn.rs b/p-token/tests/burn.rs index 6e5e2e5..df6645d 100644 --- a/p-token/tests/burn.rs +++ b/p-token/tests/burn.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn burn(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/burn_checked.rs b/p-token/tests/burn_checked.rs index a008262..c2256fd 100644 --- a/p-token/tests/burn_checked.rs +++ b/p-token/tests/burn_checked.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn burn_checked(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/close_account.rs b/p-token/tests/close_account.rs index 8a73432..d4ece1c 100644 --- a/p-token/tests/close_account.rs +++ b/p-token/tests/close_account.rs @@ -13,7 +13,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn close_account(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/freeze_account.rs b/p-token/tests/freeze_account.rs index d5fb3af..2f34b18 100644 --- a/p-token/tests/freeze_account.rs +++ b/p-token/tests/freeze_account.rs @@ -15,7 +15,7 @@ use spl_token::state::AccountState; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn freeze_account(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs index 4c491bb..17a2c11 100644 --- a/p-token/tests/initialize_account.rs +++ b/p-token/tests/initialize_account.rs @@ -15,7 +15,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_account2.rs b/p-token/tests/initialize_account2.rs index 9f250e4..2ec0805 100644 --- a/p-token/tests/initialize_account2.rs +++ b/p-token/tests/initialize_account2.rs @@ -15,7 +15,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account2(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_account3.rs b/p-token/tests/initialize_account3.rs index 7fee802..c418fc0 100644 --- a/p-token/tests/initialize_account3.rs +++ b/p-token/tests/initialize_account3.rs @@ -15,7 +15,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_account3(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index e94b57f..94406bd 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -19,7 +19,7 @@ use spl_token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index b0d7fa1..04ce4d4 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -19,7 +19,7 @@ use spl_token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_mint2(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 5cf9e34..13a518d 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -16,7 +16,7 @@ use spl_token::state::Multisig; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index 443a988..40cf084 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -16,7 +16,7 @@ use spl_token::state::Multisig; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn initialize_multisig2(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index 9cafae3..75626cb 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn mint_to(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs index 1d0cb72..56fab40 100644 --- a/p-token/tests/mint_to_checked.rs +++ b/p-token/tests/mint_to_checked.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn mint_to_checked(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/revoke.rs b/p-token/tests/revoke.rs index 689c48c..9ba9c7f 100644 --- a/p-token/tests/revoke.rs +++ b/p-token/tests/revoke.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn revoke(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/set_authority.rs b/p-token/tests/set_authority.rs index 977d22e..8d3f422 100644 --- a/p-token/tests/set_authority.rs +++ b/p-token/tests/set_authority.rs @@ -16,7 +16,7 @@ use spl_token::instruction::AuthorityType; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn set_authority(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/thaw_account.rs b/p-token/tests/thaw_account.rs index 6fe5762..4d7f957 100644 --- a/p-token/tests/thaw_account.rs +++ b/p-token/tests/thaw_account.rs @@ -15,7 +15,7 @@ use spl_token::state::AccountState; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn thaw_account(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index 16491c2..357ccb6 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn transfer(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs index d03c9f5..080bc77 100644 --- a/p-token/tests/transfer_checked.rs +++ b/p-token/tests/transfer_checked.rs @@ -14,7 +14,7 @@ use solana_sdk::{ #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn transfer_checked(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/p-token/tests/ui_amount_to_amount.rs b/p-token/tests/ui_amount_to_amount.rs index 3b1a6db..37a8788 100644 --- a/p-token/tests/ui_amount_to_amount.rs +++ b/p-token/tests/ui_amount_to_amount.rs @@ -9,7 +9,7 @@ use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] async fn ui_amount_to_amount(token_program: Pubkey) { - let mut context = ProgramTest::new("token_program", TOKEN_PROGRAM_ID, None) + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; diff --git a/package.json b/package.json index 07c04bf..77a5526 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,9 @@ "rust:spellcheck": "cargo spellcheck --code 1", "rust:audit": "zx ./scripts/rust/audit.mjs", "rust:publish": "zx ./scripts/rust/publish.mjs", - "rust:semver": "cargo semver-checks" + "rust:semver": "cargo semver-checks", + "p-token:build": "zx ./scripts/rust/build-sbf.mjs p-token", + "p-token:test": "zx ./scripts/rust/test-sbf.mjs p-token" }, "devDependencies": { "@codama/renderers-js": "^1.2.7", From 3daf44899f0bd71c879d28dffdfb788dd944f3c5 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Mon, 10 Mar 2025 14:54:02 +0000 Subject: [PATCH 317/335] p-token: Fix review comments (#32) * Update workspace * Rename interface crate * Fix spelling * [wip]: Fix review comments * [wip]: More fixes * A few more fixes * Fix instruction data validation --- Cargo.lock | 35 ++- interface/Cargo.toml | 4 + interface/src/instruction.rs | 280 ++++++++++-------- interface/src/state/account.rs | 6 +- interface/src/state/mint.rs | 8 +- interface/src/state/mod.rs | 16 +- interface/src/state/multisig.rs | 12 +- p-token/src/entrypoint.rs | 62 ++-- p-token/src/processor/approve_checked.rs | 22 +- p-token/src/processor/burn_checked.rs | 10 +- p-token/src/processor/close_account.rs | 15 +- .../src/processor/get_account_data_size.rs | 2 +- p-token/src/processor/initialize_account2.rs | 17 +- p-token/src/processor/initialize_account3.rs | 17 +- .../processor/initialize_immutable_owner.rs | 4 +- p-token/src/processor/initialize_mint.rs | 122 +------- p-token/src/processor/initialize_mint2.rs | 2 +- p-token/src/processor/mint_to_checked.rs | 10 +- p-token/src/processor/mod.rs | 64 ++-- p-token/src/processor/set_authority.rs | 65 ++-- p-token/src/processor/shared/burn.rs | 12 +- .../processor/shared/initialize_account.rs | 16 +- .../src/processor/shared/initialize_mint.rs | 89 ++++++ .../processor/shared/initialize_multisig.rs | 8 +- p-token/src/processor/shared/mint_to.rs | 11 +- p-token/src/processor/shared/mod.rs | 1 + .../processor/shared/toggle_account_state.rs | 4 +- p-token/src/processor/shared/transfer.rs | 27 +- p-token/src/processor/transfer_checked.rs | 10 +- 29 files changed, 461 insertions(+), 490 deletions(-) create mode 100644 p-token/src/processor/shared/initialize_mint.rs diff --git a/Cargo.lock b/Cargo.lock index c75292c..f30c2e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1638,6 +1638,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -5666,8 +5672,8 @@ dependencies = [ "solana-vote", "solana-vote-program", "static_assertions", - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "symlink", "tar", "tempfile", @@ -6784,6 +6790,8 @@ version = "0.0.0" dependencies = [ "pinocchio", "pinocchio-pubkey", + "strum 0.27.1", + "strum_macros 0.27.1", ] [[package]] @@ -6810,22 +6818,41 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros", + "strum_macros 0.24.3", ] +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" + [[package]] name = "strum_macros" version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.96", +] + [[package]] name = "subtle" version = "2.6.1" diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 2e3ae9e..69118d0 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -14,3 +14,7 @@ crate-type = ["rlib"] [dependencies] pinocchio = { version = "0.7", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } pinocchio-pubkey = { version = "0.2", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } + +[dev-dependencies] +strum = "0.27" +strum_macros = "0.27" diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index f928cc3..e0f747e 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -1,13 +1,12 @@ //! Instruction types. -use pinocchio::{program_error::ProgramError, pubkey::Pubkey}; - -use crate::error::TokenError; +use pinocchio::program_error::ProgramError; /// Instructions supported by the token program. -#[repr(C)] +#[repr(u8)] #[derive(Clone, Debug, PartialEq)] -pub enum TokenInstruction<'a> { +#[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))] +pub enum TokenInstruction { /// Initializes a new mint and optionally deposits all the newly minted /// tokens in an account. /// @@ -20,15 +19,14 @@ pub enum TokenInstruction<'a> { /// Accounts expected by this instruction: /// /// 0. `[writable]` The mint to initialize. - /// 1. `[]` Rent sysvar - InitializeMint { - /// Number of base 10 digits to the right of the decimal place. - decimals: u8, - /// The authority/multisignature to mint tokens. - mint_authority: Pubkey, - /// The freeze authority/multisignature of the mint. - freeze_authority: Option, - }, + /// 1. `[]` Rent sysvar. + /// + /// Data expected by this instruction: + /// + /// - `u8` The number of base 10 digits to the right of the decimal place. + /// - `Pubkey` The authority/multisignature to mint tokens. + /// - `Option` The freeze authority/multisignature of the mint. + InitializeMint, /// Initializes a new account to hold tokens. If this account is associated /// with the native mint then the token balance of the initialized account @@ -47,7 +45,7 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The account to initialize. /// 1. `[]` The mint this account will be associated with. /// 2. `[]` The new account's owner/multisignature. - /// 3. `[]` Rent sysvar + /// 3. `[]` Rent sysvar. InitializeAccount, /// Initializes a multisignature account with N provided signers. @@ -66,13 +64,13 @@ pub enum TokenInstruction<'a> { /// Accounts expected by this instruction: /// /// 0. `[writable]` The multisignature account to initialize. - /// 1. `[]` Rent sysvar + /// 1. `[]` Rent sysvar. /// 2. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <= 11`. - InitializeMultisig { - /// The number of signers (M) required to validate this multisignature - /// account. - m: u8, - }, + /// + /// Data expected by this instruction: + /// + /// - `u8` The number of signers (M) required to validate this multisignature account. + InitializeMultisig, /// Transfers tokens from one account to another either directly or via a /// delegate. If this account is associated with the native mint then equal @@ -91,10 +89,11 @@ pub enum TokenInstruction<'a> { /// 1. `[writable]` The destination account. /// 2. `[]` The source account's multisignature owner/delegate. /// 3. `..+M` `[signer]` M signer accounts. - Transfer { - /// The amount of tokens to transfer. - amount: u64, - }, + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of tokens to transfer. + Transfer, /// Approves a delegate. A delegate is given the authority over tokens on /// behalf of the source account's owner. @@ -110,11 +109,12 @@ pub enum TokenInstruction<'a> { /// 0. `[writable]` The source account. /// 1. `[]` The delegate. /// 2. `[]` The source account's multisignature owner. - /// 3. `..+M` `[signer]` M signer accounts - Approve { - /// The amount of tokens the delegate is approved for. - amount: u64, - }, + /// 3. `..+M` `[signer]` M signer accounts. + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of tokens the delegate is approved for. + Approve, /// Revokes the delegate's authority. /// @@ -127,7 +127,7 @@ pub enum TokenInstruction<'a> { /// * Multisignature owner /// 0. `[writable]` The source account. /// 1. `[]` The source account's multisignature owner. - /// 2. `..+M` `[signer]` M signer accounts + /// 2. `..+M` `[signer]` M signer accounts. Revoke, /// Sets a new authority of a mint or account. @@ -141,13 +141,13 @@ pub enum TokenInstruction<'a> { /// * Multisignature authority /// 0. `[writable]` The mint or account to change the authority of. /// 1. `[]` The mint's or account's current multisignature authority. - /// 2. `..+M` `[signer]` M signer accounts - SetAuthority { - /// The type of authority to update. - authority_type: AuthorityType, - /// The new authority - new_authority: Option, - }, + /// 2. `..+M` `[signer]` M signer accounts. + /// + /// Data expected by this instruction: + /// + /// - `AuthorityType` The type of authority to update. + /// - `Option` The new authority. + SetAuthority, /// Mints new tokens to an account. The native mint does not support /// minting. @@ -164,10 +164,11 @@ pub enum TokenInstruction<'a> { /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. /// 3. `..+M` `[signer]` M signer accounts. - MintTo { - /// The amount of new tokens to mint. - amount: u64, - }, + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of new tokens to mint. + MintTo, /// Burns tokens by removing them from an account. `Burn` does not support /// accounts associated with the native mint, use `CloseAccount` instead. @@ -184,10 +185,11 @@ pub enum TokenInstruction<'a> { /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. /// 3. `..+M` `[signer]` M signer accounts. - Burn { - /// The amount of tokens to burn. - amount: u64, - }, + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of tokens to burn. + Burn, /// Close an account by transferring all its SOL to the destination account. /// Non-native accounts may only be closed if its token amount is zero. @@ -262,12 +264,12 @@ pub enum TokenInstruction<'a> { /// 2. `[writable]` The destination account. /// 3. `[]` The source account's multisignature owner/delegate. /// 4. `..+M` `[signer]` M signer accounts. - TransferChecked { - /// The amount of tokens to transfer. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of tokens to transfer. + /// - `u8` Expected number of base 10 digits to the right of the decimal place. + TransferChecked, /// Approves a delegate. A delegate is given the authority over tokens on /// behalf of the source account's owner. @@ -289,13 +291,13 @@ pub enum TokenInstruction<'a> { /// 1. `[]` The token mint. /// 2. `[]` The delegate. /// 3. `[]` The source account's multisignature owner. - /// 4. `..+M` `[signer]` M signer accounts - ApproveChecked { - /// The amount of tokens the delegate is approved for. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, + /// 4. `..+M` `[signer]` M signer accounts. + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of tokens the delegate is approved for. + /// - `u8` Expected number of base 10 digits to the right of the decimal place. + ApproveChecked, /// Mints new tokens to an account. The native mint does not support /// minting. @@ -316,12 +318,12 @@ pub enum TokenInstruction<'a> { /// 1. `[writable]` The account to mint tokens to. /// 2. `[]` The mint's multisignature mint-tokens authority. /// 3. `..+M` `[signer]` M signer accounts. - MintToChecked { - /// The amount of new tokens to mint. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of new tokens to mint. + /// - `u8` Expected number of base 10 digits to the right of the decimal place. + MintToChecked, /// Burns tokens by removing them from an account. [`BurnChecked`] does not /// support accounts associated with the native mint, use `CloseAccount` @@ -343,12 +345,12 @@ pub enum TokenInstruction<'a> { /// 1. `[writable]` The token mint. /// 2. `[]` The account's multisignature owner/delegate. /// 3. `..+M` `[signer]` M signer accounts. - BurnChecked { - /// The amount of tokens to burn. - amount: u64, - /// Expected number of base 10 digits to the right of the decimal place. - decimals: u8, - }, + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of tokens to burn. + /// - `u8` Expected number of base 10 digits to the right of the decimal place. + BurnChecked, /// Like [`InitializeAccount`], but the owner pubkey is passed via instruction /// data rather than the accounts list. This variant may be preferable @@ -359,11 +361,12 @@ pub enum TokenInstruction<'a> { /// /// 0. `[writable]` The account to initialize. /// 1. `[]` The mint this account will be associated with. - /// 3. `[]` Rent sysvar - InitializeAccount2 { - /// The new account's owner/multisignature. - owner: Pubkey, - }, + /// 2. `[]` Rent sysvar. + /// + /// Data expected by this instruction: + /// + /// - `Pubkey` The new account's owner/multisignature. + InitializeAccount2, /// Given a wrapped / native token account (a token account containing SOL) /// updates its amount field based on the account's underlying `lamports`. @@ -384,10 +387,11 @@ pub enum TokenInstruction<'a> { /// /// 0. `[writable]` The account to initialize. /// 1. `[]` The mint this account will be associated with. - InitializeAccount3 { - /// The new account's owner/multisignature. - owner: Pubkey, - }, + /// + /// Data expected by this instruction: + /// + /// - `Pubkey` The new account's owner/multisignature. + InitializeAccount3, /// Like [`InitializeMultisig`], but does not require the Rent sysvar to be /// provided @@ -396,11 +400,11 @@ pub enum TokenInstruction<'a> { /// /// 0. `[writable]` The multisignature account to initialize. /// 1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <= 11`. - InitializeMultisig2 { - /// The number of signers (M) required to validate this multisignature - /// account. - m: u8, - }, + /// + /// Data expected by this instruction: + /// + /// - `u8` The number of signers (M) required to validate this multisignature account. + InitializeMultisig2, /// Like [`InitializeMint`], but does not require the Rent sysvar to be /// provided @@ -408,14 +412,13 @@ pub enum TokenInstruction<'a> { /// Accounts expected by this instruction: /// /// 0. `[writable]` The mint to initialize. - InitializeMint2 { - /// Number of base 10 digits to the right of the decimal place. - decimals: u8, - /// The authority/multisignature to mint tokens. - mint_authority: Pubkey, - /// The freeze authority/multisignature of the mint. - freeze_authority: Option, - }, + /// + /// Data expected by this instruction: + /// + /// - `u8` The number of base 10 digits to the right of the decimal place. + /// - `Pubkey` The authority/multisignature to mint tokens. + /// - `Option` The freeze authority/multisignature of the mint. + InitializeMint2, /// Gets the required size of an account for the given mint as a /// little-endian `u64`. @@ -425,8 +428,8 @@ pub enum TokenInstruction<'a> { /// /// Accounts expected by this instruction: /// - /// 0. `[]` The mint to calculate for - GetAccountDataSize, // typically, there's also data, but this program ignores it + /// 0. `[]` The mint to calculate for. + GetAccountDataSize, /// Initialize the Immutable Owner extension for the given token account /// @@ -439,9 +442,6 @@ pub enum TokenInstruction<'a> { /// Accounts expected by this instruction: /// /// 0. `[writable]` The account to initialize. - /// - /// Data expected by this instruction: - /// None InitializeImmutableOwner, /// Convert an Amount of tokens to a `UiAmount` `string`, using the given @@ -456,10 +456,11 @@ pub enum TokenInstruction<'a> { /// Accounts expected by this instruction: /// /// 0. `[]` The mint to calculate for - AmountToUiAmount { - /// The amount of tokens to reformat. - amount: u64, - }, + /// + /// Data expected by this instruction: + /// + /// - `u64` The amount of tokens to reformat. + AmountToUiAmount, /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount, using /// the given mint. In this version of the program, the mint can only @@ -470,19 +471,34 @@ pub enum TokenInstruction<'a> { /// /// Accounts expected by this instruction: /// - /// 0. `[]` The mint to calculate for - UiAmountToAmount { - /// The `ui_amount` of tokens to reformat. - ui_amount: &'a str, - }, + /// 0. `[]` The mint to calculate for. + /// + /// Data expected by this instruction: + /// + /// - `&str` The `ui_amount` of tokens to reformat. + UiAmountToAmount, // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the // latter remains a superset of this instruction set. New variants also need to be added to // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility } +impl TryFrom for TokenInstruction { + type Error = ProgramError; + + #[inline(always)] + fn try_from(value: u8) -> Result { + match value { + // SAFETY: `value` is guaranteed to be in the range of the enum variants. + 0..=24 => Ok(unsafe { core::mem::transmute::(value) }), + _ => Err(ProgramError::InvalidInstructionData), + } + } +} + /// Specifies the authority type for `SetAuthority` instructions #[repr(u8)] #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(test, derive(strum_macros::FromRepr, strum_macros::EnumIter))] pub enum AuthorityType { /// Authority to mint new tokens MintTokens, @@ -494,23 +510,45 @@ pub enum AuthorityType { CloseAccount, } -impl AuthorityType { - pub fn into(&self) -> u8 { - match self { - AuthorityType::MintTokens => 0, - AuthorityType::FreezeAccount => 1, - AuthorityType::AccountOwner => 2, - AuthorityType::CloseAccount => 3, +impl TryFrom for AuthorityType { + type Error = ProgramError; + + #[inline(always)] + fn try_from(value: u8) -> Result { + match value { + // SAFETY: `value` is guaranteed to be in the range of the enum variants. + 0..=3 => Ok(unsafe { core::mem::transmute::(value) }), + _ => Err(ProgramError::InvalidInstructionData), + } + } +} + +#[cfg(test)] +mod tests { + use super::{AuthorityType, TokenInstruction}; + use strum::IntoEnumIterator; + + #[test] + fn test_token_instruction_from_u8_exhaustive() { + for variant in TokenInstruction::iter() { + let variant_u8 = variant.clone() as u8; + assert_eq!( + TokenInstruction::from_repr(variant_u8), + Some(TokenInstruction::try_from(variant_u8).unwrap()) + ); + assert_eq!(TokenInstruction::try_from(variant_u8).unwrap(), variant); } } - pub fn from(index: u8) -> Result { - match index { - 0 => Ok(AuthorityType::MintTokens), - 1 => Ok(AuthorityType::FreezeAccount), - 2 => Ok(AuthorityType::AccountOwner), - 3 => Ok(AuthorityType::CloseAccount), - _ => Err(TokenError::InvalidInstruction.into()), + #[test] + fn test_authority_type_from_u8_exhaustive() { + for variant in AuthorityType::iter() { + let variant_u8 = variant.clone() as u8; + assert_eq!( + AuthorityType::from_repr(variant_u8), + Some(AuthorityType::try_from(variant_u8).unwrap()) + ); + assert_eq!(AuthorityType::try_from(variant_u8).unwrap(), variant); } } } diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index a4cf6d3..9e5e2c0 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -1,9 +1,9 @@ use pinocchio::pubkey::Pubkey; -use super::{account_state::AccountState, COption, Initializable, RawType}; +use super::{account_state::AccountState, COption, Initializable, Transmutable}; /// Incinerator address. -const INCINERATOR_ID: Pubkey = +pub const INCINERATOR_ID: Pubkey = pinocchio_pubkey::pubkey!("1nc1nerator11111111111111111111111111111111"); /// System program id. @@ -140,7 +140,7 @@ impl Account { } } -impl RawType for Account { +impl Transmutable for Account { const LEN: usize = core::mem::size_of::(); } diff --git a/interface/src/state/mint.rs b/interface/src/state/mint.rs index 3b4d41b..46d6168 100644 --- a/interface/src/state/mint.rs +++ b/interface/src/state/mint.rs @@ -1,6 +1,6 @@ use pinocchio::pubkey::Pubkey; -use super::{COption, Initializable, RawType}; +use super::{COption, Initializable, Transmutable}; /// Internal representation of a mint data. #[repr(C)] @@ -38,8 +38,8 @@ impl Mint { } #[inline(always)] - pub fn set_initialized(&mut self, value: bool) { - self.is_initialized = value as u8; + pub fn set_initialized(&mut self) { + self.is_initialized = 1; } #[inline(always)] @@ -83,7 +83,7 @@ impl Mint { } } -impl RawType for Mint { +impl Transmutable for Mint { /// The length of the `Mint` account data. const LEN: usize = core::mem::size_of::(); } diff --git a/interface/src/state/mod.rs b/interface/src/state/mod.rs index b7c35df..28ba9f7 100644 --- a/interface/src/state/mod.rs +++ b/interface/src/state/mod.rs @@ -8,11 +8,11 @@ pub mod multisig; /// Type alias for fields represented as `COption`. pub type COption = ([u8; 4], T); -/// Marker trait for types that can cast from a raw pointer. +/// Marker trait for types that can be cast from a raw pointer. /// /// It is up to the type implementing this trait to guarantee that the cast is safe, -/// i.e., that the fields of the type are well aligned and there are no padding bytes. -pub trait RawType { +/// i.e., the fields of the type are well aligned and there are no padding bytes. +pub trait Transmutable { /// The length of the type. /// /// This must be equal to the size of each individual field in the type. @@ -31,7 +31,7 @@ pub trait Initializable { /// /// The caller must ensure that `bytes` contains a valid representation of `T`. #[inline(always)] -pub unsafe fn load(bytes: &[u8]) -> Result<&T, ProgramError> { +pub unsafe fn load(bytes: &[u8]) -> Result<&T, ProgramError> { load_unchecked(bytes).and_then(|t: &T| { // checks if the data is initialized if t.is_initialized() { @@ -50,7 +50,7 @@ pub unsafe fn load(bytes: &[u8]) -> Result<&T, Progr /// /// The caller must ensure that `bytes` contains a valid representation of `T`. #[inline(always)] -pub unsafe fn load_unchecked(bytes: &[u8]) -> Result<&T, ProgramError> { +pub unsafe fn load_unchecked(bytes: &[u8]) -> Result<&T, ProgramError> { if bytes.len() != T::LEN { return Err(ProgramError::InvalidAccountData); } @@ -63,7 +63,7 @@ pub unsafe fn load_unchecked(bytes: &[u8]) -> Result<&T, ProgramErro /// /// The caller must ensure that `bytes` contains a valid representation of `T`. #[inline(always)] -pub unsafe fn load_mut( +pub unsafe fn load_mut( bytes: &mut [u8], ) -> Result<&mut T, ProgramError> { load_mut_unchecked(bytes).and_then(|t: &mut T| { @@ -84,7 +84,9 @@ pub unsafe fn load_mut( /// /// The caller must ensure that `bytes` contains a valid representation of `T`. #[inline(always)] -pub unsafe fn load_mut_unchecked(bytes: &mut [u8]) -> Result<&mut T, ProgramError> { +pub unsafe fn load_mut_unchecked( + bytes: &mut [u8], +) -> Result<&mut T, ProgramError> { if bytes.len() != T::LEN { return Err(ProgramError::InvalidAccountData); } diff --git a/interface/src/state/multisig.rs b/interface/src/state/multisig.rs index 920da97..d0ad7a3 100644 --- a/interface/src/state/multisig.rs +++ b/interface/src/state/multisig.rs @@ -1,12 +1,12 @@ use pinocchio::pubkey::Pubkey; -use super::{Initializable, RawType}; +use super::{Initializable, Transmutable}; /// Minimum number of multisignature signers (min N) -pub const MIN_SIGNERS: usize = 1; +pub const MIN_SIGNERS: u8 = 1; /// Maximum number of multisignature signers (max N) -pub const MAX_SIGNERS: usize = 11; +pub const MAX_SIGNERS: u8 = 11; /// Multisignature data. #[repr(C)] @@ -21,12 +21,12 @@ pub struct Multisig { is_initialized: u8, /// Signer public keys - pub signers: [Pubkey; MAX_SIGNERS], + pub signers: [Pubkey; MAX_SIGNERS as usize], } impl Multisig { /// Utility function that checks index is between [`MIN_SIGNERS`] and [`MAX_SIGNERS`]. - pub fn is_valid_signer_index(index: usize) -> bool { + pub fn is_valid_signer_index(index: u8) -> bool { (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) } @@ -36,7 +36,7 @@ impl Multisig { } } -impl RawType for Multisig { +impl Transmutable for Multisig { /// The length of the `Mint` account data. const LEN: usize = core::mem::size_of::(); } diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 0780829..80fd04e 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -2,6 +2,7 @@ use pinocchio::{ account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; +use spl_token_interface::instruction::TokenInstruction; use crate::processor::*; @@ -36,52 +37,53 @@ pub fn process_instruction( let (discriminator, instruction_data) = instruction_data .split_first() .ok_or(ProgramError::InvalidInstructionData)?; + let instruction = TokenInstruction::try_from(*discriminator)?; - match *discriminator { + match instruction { // 0 - InitializeMint - 0 => { + TokenInstruction::InitializeMint => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMint"); - process_initialize_mint(accounts, instruction_data, true) + process_initialize_mint(accounts, instruction_data) } // 3 - Transfer - 3 => { + TokenInstruction::Transfer => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Transfer"); process_transfer(accounts, instruction_data) } // 7 - MintTo - 7 => { + TokenInstruction::MintTo => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: MintTo"); process_mint_to(accounts, instruction_data) } // 9 - CloseAccount - 9 => { + TokenInstruction::CloseAccount => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: CloseAccount"); process_close_account(accounts) } // 18 - InitializeAccount3 - 18 => { + TokenInstruction::InitializeAccount3 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeAccount3"); process_initialize_account3(accounts, instruction_data) } // 20 - InitializeMint2 - 20 => { + TokenInstruction::InitializeMint2 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMint2"); process_initialize_mint2(accounts, instruction_data) } - _ => process_remaining_instruction(accounts, instruction_data, *discriminator), + _ => process_remaining_instruction(accounts, instruction_data, instruction), } } @@ -93,137 +95,137 @@ pub fn process_instruction( fn process_remaining_instruction( accounts: &[AccountInfo], instruction_data: &[u8], - discriminator: u8, + instruction: TokenInstruction, ) -> ProgramResult { - match discriminator { + match instruction { // 1 - InitializeAccount - 1 => { + TokenInstruction::InitializeAccount => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeAccount"); process_initialize_account(accounts) } // 2 - InitializeMultisig - 2 => { + TokenInstruction::InitializeMultisig => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMultisig"); process_initialize_multisig(accounts, instruction_data) } // 4 - Approve - 4 => { + TokenInstruction::Approve => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Approve"); process_approve(accounts, instruction_data) } // 5 - Revoke - 5 => { + TokenInstruction::Revoke => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Revoke"); process_revoke(accounts, instruction_data) } // 6 - SetAuthority - 6 => { + TokenInstruction::SetAuthority => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: SetAuthority"); process_set_authority(accounts, instruction_data) } // 8 - Burn - 8 => { + TokenInstruction::Burn => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Burn"); process_burn(accounts, instruction_data) } // 10 - FreezeAccount - 10 => { + TokenInstruction::FreezeAccount => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: FreezeAccount"); process_freeze_account(accounts) } // 11 - ThawAccount - 11 => { + TokenInstruction::ThawAccount => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ThawAccount"); process_thaw_account(accounts) } // 12 - TransferChecked - 12 => { + TokenInstruction::TransferChecked => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: TransferChecked"); process_transfer_checked(accounts, instruction_data) } // 13 - ApproveChecked - 13 => { + TokenInstruction::ApproveChecked => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ApproveChecked"); process_approve_checked(accounts, instruction_data) } // 14 - MintToChecked - 14 => { + TokenInstruction::MintToChecked => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: MintToChecked"); process_mint_to_checked(accounts, instruction_data) } // 15 - BurnChecked - 15 => { + TokenInstruction::BurnChecked => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: BurnChecked"); process_burn_checked(accounts, instruction_data) } // 16 - InitializeAccount2 - 16 => { + TokenInstruction::InitializeAccount2 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeAccount2"); process_initialize_account2(accounts, instruction_data) } // 17 - SyncNative - 17 => { + TokenInstruction::SyncNative => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: SyncNative"); process_sync_native(accounts) } // 19 - InitializeMultisig2 - 19 => { + TokenInstruction::InitializeMultisig2 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMultisig2"); process_initialize_multisig2(accounts, instruction_data) } // 21 - GetAccountDataSize - 21 => { + TokenInstruction::GetAccountDataSize => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: GetAccountDataSize"); process_get_account_data_size(accounts) } // 22 - InitializeImmutableOwner - 22 => { + TokenInstruction::InitializeImmutableOwner => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeImmutableOwner"); process_initialize_immutable_owner(accounts) } // 23 - AmountToUiAmount - 23 => { + TokenInstruction::AmountToUiAmount => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: AmountToUiAmount"); process_amount_to_ui_amount(accounts, instruction_data) } // 24 - UiAmountToAmount - 24 => { + TokenInstruction::UiAmountToAmount => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: UiAmountToAmount"); diff --git a/p-token/src/processor/approve_checked.rs b/p-token/src/processor/approve_checked.rs index 580a93d..f9a8230 100644 --- a/p-token/src/processor/approve_checked.rs +++ b/p-token/src/processor/approve_checked.rs @@ -4,16 +4,16 @@ use super::shared; #[inline(always)] pub fn process_approve_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); - let amount = u64::from_le_bytes( - amount - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + // expected u64 (8) + u8 (1) + let (amount, decimals) = if instruction_data.len() == 9 { + let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); + ( + u64::from_le_bytes(amount.try_into().unwrap()), + decimals.first().copied(), + ) + } else { + return Err(ProgramError::InvalidInstructionData); + }; - shared::approve::process_approve( - accounts, - amount, - Some(*decimals.first().ok_or(ProgramError::InvalidAccountData)?), - ) + shared::approve::process_approve(accounts, amount, decimals) } diff --git a/p-token/src/processor/burn_checked.rs b/p-token/src/processor/burn_checked.rs index 88a745d..2c8a134 100644 --- a/p-token/src/processor/burn_checked.rs +++ b/p-token/src/processor/burn_checked.rs @@ -8,16 +8,12 @@ pub fn process_burn_checked(accounts: &[AccountInfo], instruction_data: &[u8]) - let (amount, decimals) = if instruction_data.len() == 9 { let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); ( - u64::from_le_bytes( - amount - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ), - decimals.first(), + u64::from_le_bytes(amount.try_into().unwrap()), + decimals.first().copied(), ) } else { return Err(ProgramError::InvalidInstructionData); }; - shared::burn::process_burn(accounts, amount, decimals.copied()) + shared::burn::process_burn(accounts, amount, decimals) } diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs index 618b567..21cfc4d 100644 --- a/p-token/src/processor/close_account.rs +++ b/p-token/src/processor/close_account.rs @@ -1,19 +1,14 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, -}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use spl_token_interface::{ error::TokenError, - state::{account::Account, load}, + state::{ + account::{Account, INCINERATOR_ID}, + load, + }, }; use super::validate_owner; -/// Incinerator (`1nc1nerator11111111111111111111111111111111`) address. -const INCINERATOR_ID: Pubkey = [ - 0, 51, 144, 114, 141, 52, 17, 96, 121, 189, 201, 17, 191, 255, 0, 219, 212, 77, 46, 205, 204, - 247, 156, 166, 225, 0, 56, 225, 0, 0, 0, 0, -]; - #[inline(always)] pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { let [source_account_info, destination_account_info, authority_info, remaining @ ..] = accounts diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index b789317..690abf1 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -3,7 +3,7 @@ use pinocchio::{ }; use spl_token_interface::{ error::TokenError, - state::{account::Account, load, mint::Mint, RawType}, + state::{account::Account, load, mint::Mint, Transmutable}, }; use super::check_account_owner; diff --git a/p-token/src/processor/initialize_account2.rs b/p-token/src/processor/initialize_account2.rs index 185c291..f28ec3c 100644 --- a/p-token/src/processor/initialize_account2.rs +++ b/p-token/src/processor/initialize_account2.rs @@ -1,8 +1,5 @@ use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::{Pubkey, PUBKEY_BYTES}, - ProgramResult, + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; use super::shared; @@ -12,13 +9,9 @@ pub fn process_initialize_account2( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - // SAFETY: validate `instruction_data` length. - let owner = unsafe { - if instruction_data.len() != PUBKEY_BYTES { - return Err(ProgramError::InvalidInstructionData); - } else { - &*(instruction_data.as_ptr() as *const Pubkey) - } - }; + let owner: &Pubkey = instruction_data + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?; + shared::initialize_account::process_initialize_account(accounts, Some(owner), true) } diff --git a/p-token/src/processor/initialize_account3.rs b/p-token/src/processor/initialize_account3.rs index 54e5501..8aca410 100644 --- a/p-token/src/processor/initialize_account3.rs +++ b/p-token/src/processor/initialize_account3.rs @@ -1,8 +1,5 @@ use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::{Pubkey, PUBKEY_BYTES}, - ProgramResult, + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; use super::shared; @@ -12,13 +9,9 @@ pub fn process_initialize_account3( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - // SAFETY: validate `instruction_data` length. - let owner = unsafe { - if instruction_data.len() != PUBKEY_BYTES { - return Err(ProgramError::InvalidInstructionData); - } else { - &*(instruction_data.as_ptr() as *const Pubkey) - } - }; + let owner: &Pubkey = instruction_data + .try_into() + .map_err(|_error| ProgramError::InvalidInstructionData)?; + shared::initialize_account::process_initialize_account(accounts, Some(owner), false) } diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs index 7a59336..db39cbd 100644 --- a/p-token/src/processor/initialize_immutable_owner.rs +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -1,4 +1,4 @@ -use pinocchio::{account_info::AccountInfo, msg, program_error::ProgramError, ProgramResult}; +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; use spl_token_interface::{ error::TokenError, state::{account::Account, load_unchecked, Initializable}, @@ -14,6 +14,6 @@ pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramRe if account.is_initialized() { return Err(TokenError::AlreadyInUse.into()); } - msg!("Please upgrade to SPL Token 2022 for immutable owner support"); + // Please upgrade to SPL Token 2022 for immutable owner support. Ok(()) } diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 935acfd..3d5b5f5 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -1,120 +1,8 @@ -use core::{marker::PhantomData, mem::size_of}; -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::Pubkey, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, -}; -use spl_token_interface::{ - error::TokenError, - state::{load_mut_unchecked, mint::Mint, Initializable}, -}; +use pinocchio::{account_info::AccountInfo, ProgramResult}; -#[inline(always)] -pub fn process_initialize_mint( - accounts: &[AccountInfo], - instruction_data: &[u8], - rent_sysvar_account: bool, -) -> ProgramResult { - // Validates the instruction data. - - let args = InitializeMint::try_from_bytes(instruction_data)?; - - // Validates the accounts. - - let (mint_info, rent_sysvar_info) = if rent_sysvar_account { - let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (mint_info, Some(rent_sysvar_info)) - } else { - let [mint_info, _remaining @ ..] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - (mint_info, None) - }; - - // SAFETY: single mutable borrow to `mint_info` account data. - let mint = unsafe { load_mut_unchecked::(mint_info.borrow_mut_data_unchecked())? }; - - if mint.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } - - // Check rent-exempt status of the mint account. - - let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { - // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are - // checked by `from_account_info_unchecked`. - let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; - rent.is_exempt(mint_info.lamports(), size_of::()) - } else { - Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) - }; - - if !is_exempt { - return Err(TokenError::NotRentExempt.into()); - } - - // Initialize the mint. - - mint.set_initialized(true); - mint.set_mint_authority(args.mint_authority()); - mint.decimals = args.decimals(); +use super::shared; - if let Some(freeze_authority) = args.freeze_authority() { - mint.set_freeze_authority(freeze_authority); - } - - Ok(()) -} - -/// Instruction data for the `InitializeMint` instruction. -pub struct InitializeMint<'a> { - raw: *const u8, - - _data: PhantomData<&'a [u8]>, -} - -impl InitializeMint<'_> { - #[inline] - pub fn try_from_bytes(bytes: &[u8]) -> Result { - // The minimum expected size of the instruction data. - // - decimals (1 byte) - // - mint_authority (32 bytes) - // - option + freeze_authority (1 byte + 32 bytes) - if bytes.len() < 34 || (bytes[33] == 1 && bytes.len() < 66) { - return Err(ProgramError::InvalidInstructionData); - } - - Ok(InitializeMint { - raw: bytes.as_ptr(), - _data: PhantomData, - }) - } - - #[inline] - pub fn decimals(&self) -> u8 { - // SAFETY: the `bytes` length was validated in `try_from_bytes`. - unsafe { *self.raw } - } - - #[inline] - pub fn mint_authority(&self) -> &Pubkey { - // SAFETY: the `bytes` length was validated in `try_from_bytes`. - unsafe { &*(self.raw.add(1) as *const Pubkey) } - } - - #[inline] - pub fn freeze_authority(&self) -> Option<&Pubkey> { - // SAFETY: the `bytes` length was validated in `try_from_bytes`. - unsafe { - if *self.raw.add(33) == 0 { - Option::None - } else { - Option::Some(&*(self.raw.add(34) as *const Pubkey)) - } - } - } +#[inline(always)] +pub fn process_initialize_mint(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { + shared::initialize_mint::process_initialize_mint(accounts, instruction_data, true) } diff --git a/p-token/src/processor/initialize_mint2.rs b/p-token/src/processor/initialize_mint2.rs index 0f1f07d..41b2c0b 100644 --- a/p-token/src/processor/initialize_mint2.rs +++ b/p-token/src/processor/initialize_mint2.rs @@ -1,6 +1,6 @@ use pinocchio::{account_info::AccountInfo, ProgramResult}; -use super::initialize_mint::process_initialize_mint; +use super::shared::initialize_mint::process_initialize_mint; #[inline(always)] pub fn process_initialize_mint2( diff --git a/p-token/src/processor/mint_to_checked.rs b/p-token/src/processor/mint_to_checked.rs index ebfcdea..2386bf5 100644 --- a/p-token/src/processor/mint_to_checked.rs +++ b/p-token/src/processor/mint_to_checked.rs @@ -8,16 +8,12 @@ pub fn process_mint_to_checked(accounts: &[AccountInfo], instruction_data: &[u8] let (amount, decimals) = if instruction_data.len() == 9 { let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); ( - u64::from_le_bytes( - amount - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ), - decimals.first(), + u64::from_le_bytes(amount.try_into().unwrap()), + decimals.first().copied(), ) } else { return Err(ProgramError::InvalidInstructionData); }; - shared::mint_to::process_mint_to(accounts, amount, decimals.copied()) + shared::mint_to::process_mint_to(accounts, amount, decimals) } diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index ee807d4..96e7586 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -1,11 +1,6 @@ -use core::{ - cmp::max, - mem::MaybeUninit, - slice::{from_raw_parts, from_raw_parts_mut}, - str::from_utf8_unchecked, -}; +use core::{slice::from_raw_parts, str::from_utf8_unchecked}; use pinocchio::{ - account_info::AccountInfo, memory::sol_memcpy, program_error::ProgramError, pubkey::Pubkey, + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, syscalls::sol_memcpy_, ProgramResult, }; use spl_token_interface::{ @@ -14,7 +9,7 @@ use spl_token_interface::{ state::{ load, multisig::{Multisig, MAX_SIGNERS}, - RawType, + Transmutable, }, }; @@ -72,9 +67,6 @@ pub use transfer::process_transfer; pub use transfer_checked::process_transfer_checked; pub use ui_amount_to_amount::process_ui_amount_to_amount; -/// An uninitialized byte. -const UNINIT_BYTE: MaybeUninit = MaybeUninit::uninit(); - /// Maximum number of digits in a formatted `u64`. /// /// The maximum number of digits is equal to the maximum number @@ -95,7 +87,8 @@ fn check_account_owner(account_info: &AccountInfo) -> ProgramResult { /// Validates owner(s) are present. /// /// Note that `owner_account_info` will be immutable borrowed when it represents -/// a multisig account. +/// a multisig account, therefore it should not have any mutable borrows when +/// calling this function. #[inline(always)] fn validate_owner( expected_owner: &Pubkey, @@ -110,11 +103,13 @@ fn validate_owner( && owner_account_info.owner() == &TOKEN_PROGRAM_ID { // SAFETY: the caller guarantees that there are no mutable borrows of `owner_account_info` - // account data and the `load` validates that the account is initialized. + // account data and the `load` validates that the account is initialized; additionally, + // `Multisig` accounts are only ever loaded in this function, which means that previous + // loads will have already failed by the time we get here. let multisig = unsafe { load::(owner_account_info.borrow_data_unchecked())? }; let mut num_signers = 0; - let mut matched = [false; MAX_SIGNERS]; + let mut matched = [false; MAX_SIGNERS as usize]; for signer in signers.iter() { for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() { @@ -152,54 +147,35 @@ fn try_ui_amount_into_amount(ui_amount: &str, decimals: u8) -> Result decimals - || (length + expected_after_decimal_length) > MAX_FORMATTED_DIGITS + || (length + decimals) > MAX_FORMATTED_DIGITS { return Err(ProgramError::InvalidArgument); } - let mut digits = [UNINIT_BYTE; MAX_FORMATTED_DIGITS]; - // SAFETY: `digits` is an array of `MaybeUninit`, which has the same - // memory layout as `u8`. - let slice: &mut [u8] = - unsafe { from_raw_parts_mut(digits.as_mut_ptr() as *mut _, MAX_FORMATTED_DIGITS) }; + let mut digits = [b'0'; MAX_FORMATTED_DIGITS]; // SAFETY: the total length of `amount_str` and `after_decimal` is less than - // `MAX_DIGITS_U64`. + // `MAX_FORMATTED_DIGITS`. unsafe { - sol_memcpy(slice, amount_str.as_bytes(), length); + sol_memcpy_(digits.as_mut_ptr(), amount_str.as_ptr(), length as u64); - sol_memcpy( - &mut slice[length..], - after_decimal.as_bytes(), - after_decimal.len(), + sol_memcpy_( + digits.as_mut_ptr().add(length), + after_decimal.as_ptr(), + after_decimal.len() as u64, ); } - length += after_decimal.len(); - let remaining = decimals.saturating_sub(after_decimal.len()); - - // SAFETY: `digits` is an array of `MaybeUninit`, which has the same memory - // layout as `u8`. - let ptr = unsafe { digits.as_mut_ptr().add(length) }; - - for offset in 0..remaining { - // SAFETY: `ptr` is within the bounds of `digits`. - unsafe { - (ptr.add(offset) as *mut u8).write(b'0'); - } - } - - length += remaining; + let length = amount_str.len() + decimals; // SAFETY: `digits` only contains valid UTF-8 bytes. unsafe { - from_utf8_unchecked(from_raw_parts(digits.as_ptr() as _, length)) + from_utf8_unchecked(from_raw_parts(digits.as_ptr(), length)) .parse::() .map_err(|_| ProgramError::InvalidArgument) } diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index 5da19c2..b621eeb 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -1,12 +1,10 @@ -use core::marker::PhantomData; - use pinocchio::{ account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; use spl_token_interface::{ error::TokenError, instruction::AuthorityType, - state::{account::Account, load_mut, mint::Mint, RawType}, + state::{account::Account, load_mut, mint::Mint, Transmutable}, }; use super::validate_owner; @@ -15,10 +13,22 @@ use super::validate_owner; pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { // Validates the instruction data. - let args = SetAuthority::try_from_bytes(instruction_data)?; - - let authority_type = args.authority_type()?; - let new_authority = args.new_authority(); + // SAFETY: The expected size of the instruction data is either 2 or 34 bytes: + // - authority_type (1 byte) + // - option + new_authority (1 byte + 32 bytes) + let (authority_type, new_authority) = unsafe { + match instruction_data.len() { + 2 if *instruction_data.get_unchecked(1) == 0 => ( + AuthorityType::try_from(*instruction_data.get_unchecked(0))?, + None, + ), + 34 if *instruction_data.get_unchecked(1) == 1 => ( + AuthorityType::try_from(*instruction_data.get_unchecked(0))?, + Some(&*(instruction_data.as_ptr().add(2) as *const Pubkey)), + ), + _ => return Err(ProgramError::InvalidInstructionData), + } + }; // Validates the accounts. @@ -110,44 +120,3 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) Ok(()) } - -struct SetAuthority<'a> { - raw: *const u8, - - _data: PhantomData<&'a [u8]>, -} - -impl SetAuthority<'_> { - #[inline(always)] - pub fn try_from_bytes(bytes: &[u8]) -> Result { - // The minimum expected size of the instruction data. - // - authority_type (1 byte) - // - option + new_authority (1 byte + 32 bytes) - if bytes.len() < 2 || (bytes[1] == 1 && bytes.len() < 34) { - return Err(ProgramError::InvalidInstructionData); - } - - Ok(SetAuthority { - raw: bytes.as_ptr(), - _data: PhantomData, - }) - } - - #[inline(always)] - pub fn authority_type(&self) -> Result { - // SAFETY: `bytes` length is validated in `try_from_bytes`. - unsafe { AuthorityType::from(*self.raw) } - } - - #[inline(always)] - pub fn new_authority(&self) -> Option<&Pubkey> { - // SAFETY: `bytes` length is validated in `try_from_bytes`. - unsafe { - if *self.raw.add(1) == 0 { - Option::None - } else { - Option::Some(&*(self.raw.add(2) as *const Pubkey)) - } - } - } -} diff --git a/p-token/src/processor/shared/burn.rs b/p-token/src/processor/shared/burn.rs index cae712e..abb250a 100644 --- a/p-token/src/processor/shared/burn.rs +++ b/p-token/src/processor/shared/burn.rs @@ -36,7 +36,9 @@ pub fn process_burn( .ok_or(TokenError::InsufficientFunds)?; // SAFETY: single mutable borrow to `mint_info` account data and - // `load_mut` validates that the mint is initialized. + // `load_mut` validates that the mint is initialized; additionally, an + // account cannot be both a token account and a mint, so if duplicates are + // passed in, one of them will fail the `load_mut` check. let mint = unsafe { load_mut::(mint_info.borrow_mut_data_unchecked())? }; if mint_info.key() != &source_account.mint { @@ -77,11 +79,9 @@ pub fn process_burn( check_account_owner(mint_info)?; } else { source_account.set_amount(updated_source_amount); - - let mint_supply = mint - .supply() - .checked_sub(amount) - .ok_or(TokenError::Overflow)?; + // Note: The amount of a token account is always within the range of the + // mint supply (`u64`). + let mint_supply = mint.supply().checked_sub(amount).unwrap(); mint.set_supply(mint_supply); } diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index 02fcacd..b87d034 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -20,7 +20,7 @@ use crate::processor::check_account_owner; pub fn process_initialize_account( accounts: &[AccountInfo], owner: Option<&Pubkey>, - rent_sysvar_account: bool, + rent_sysvar_account_provided: bool, ) -> ProgramResult { // Accounts expected depend on whether we have the `rent_sysvar` account or not. @@ -40,7 +40,7 @@ pub fn process_initialize_account( let new_account_info_data_len = new_account_info.data_len(); - let minimum_balance = if rent_sysvar_account { + let minimum_balance = if rent_sysvar_account_provided { let rent_sysvar_info = remaining .first() .ok_or(ProgramError::NotEnoughAccountKeys)?; @@ -85,15 +85,9 @@ pub fn process_initialize_account( if is_native_mint { account.set_native(true); account.set_native_amount(minimum_balance); - // SAFETY: single mutable borrow to `new_account_info` lamports. - unsafe { - account.set_amount( - new_account_info - .borrow_lamports_unchecked() - .checked_sub(minimum_balance) - .ok_or(TokenError::Overflow)?, - ); - } + // `new_account_info` lamports are already checked to be greater than or equal + // to the minimum balance. + account.set_amount(new_account_info.lamports() - minimum_balance); } Ok(()) diff --git a/p-token/src/processor/shared/initialize_mint.rs b/p-token/src/processor/shared/initialize_mint.rs new file mode 100644 index 0000000..657f575 --- /dev/null +++ b/p-token/src/processor/shared/initialize_mint.rs @@ -0,0 +1,89 @@ +use core::mem::size_of; +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::Pubkey, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, +}; +use spl_token_interface::{ + error::TokenError, + state::{load_mut_unchecked, mint::Mint, Initializable}, +}; + +#[inline(always)] +pub fn process_initialize_mint( + accounts: &[AccountInfo], + instruction_data: &[u8], + rent_sysvar_account_provided: bool, +) -> ProgramResult { + // Validates the instruction data. + + // SAFETY: The minimum size of the instruction data is either 34 or 66 bytes: + // - decimals (1 byte) + // - mint_authority (32 bytes) + // - option + freeze_authority (1 byte + 32 bytes) + let (decimals, mint_authority, freeze_authority) = unsafe { + match instruction_data.len() { + 34 if *instruction_data.get_unchecked(33) == 0 => ( + *instruction_data.get_unchecked(0), + &*(instruction_data.as_ptr().add(1) as *const Pubkey), + None, + ), + 66 if *instruction_data.get_unchecked(33) == 1 => ( + *instruction_data.get_unchecked(0), + &*(instruction_data.as_ptr().add(1) as *const Pubkey), + Some(&*(instruction_data.as_ptr().add(34) as *const Pubkey)), + ), + _ => return Err(ProgramError::InvalidInstructionData), + } + }; + + // Validates the accounts. + + let (mint_info, rent_sysvar_info) = if rent_sysvar_account_provided { + let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (mint_info, Some(rent_sysvar_info)) + } else { + let [mint_info, _remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + (mint_info, None) + }; + + // SAFETY: single mutable borrow to `mint_info` account data. + let mint = unsafe { load_mut_unchecked::(mint_info.borrow_mut_data_unchecked())? }; + + if mint.is_initialized() { + return Err(TokenError::AlreadyInUse.into()); + } + + // Check rent-exempt status of the mint account. + + let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { + // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are + // checked by `from_account_info_unchecked`. + let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; + rent.is_exempt(mint_info.lamports(), size_of::()) + } else { + Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) + }; + + if !is_exempt { + return Err(TokenError::NotRentExempt.into()); + } + + // Initialize the mint. + + mint.set_initialized(); + mint.set_mint_authority(mint_authority); + mint.decimals = decimals; + + if let Some(freeze_authority) = freeze_authority { + mint.set_freeze_authority(freeze_authority); + } + + Ok(()) +} diff --git a/p-token/src/processor/shared/initialize_multisig.rs b/p-token/src/processor/shared/initialize_multisig.rs index fc863fb..00480ff 100644 --- a/p-token/src/processor/shared/initialize_multisig.rs +++ b/p-token/src/processor/shared/initialize_multisig.rs @@ -13,11 +13,11 @@ use spl_token_interface::{ pub fn process_initialize_multisig( accounts: &[AccountInfo], m: u8, - rent_sysvar_account: bool, + rent_sysvar_account_provided: bool, ) -> ProgramResult { // Accounts expected depend on whether we have the `rent_sysvar` account or not. - let (multisig_info, rent_sysvar_info, remaining) = if rent_sysvar_account { + let (multisig_info, rent_sysvar_info, remaining) = if rent_sysvar_account_provided { let [multisig_info, rent_sysvar_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; @@ -57,10 +57,10 @@ pub fn process_initialize_multisig( multisig.m = m; multisig.n = remaining.len() as u8; - if !Multisig::is_valid_signer_index(multisig.n as usize) { + if !Multisig::is_valid_signer_index(multisig.n) { return Err(TokenError::InvalidNumberOfProvidedSigners.into()); } - if !Multisig::is_valid_signer_index(multisig.m as usize) { + if !Multisig::is_valid_signer_index(multisig.m) { return Err(TokenError::InvalidNumberOfRequiredSigners.into()); } diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs index 3548cc4..14aabba 100644 --- a/p-token/src/processor/shared/mint_to.rs +++ b/p-token/src/processor/shared/mint_to.rs @@ -51,20 +51,19 @@ pub fn process_mint_to( } if amount == 0 { + // Validates the accounts' owner since we are not writing + // to these account. check_account_owner(mint_info)?; check_account_owner(destination_account_info)?; } else { - let destination_amount = destination_account - .amount() - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - destination_account.set_amount(destination_amount); - let mint_supply = mint .supply() .checked_add(amount) .ok_or(TokenError::Overflow)?; mint.set_supply(mint_supply); + + // This should not fail since there is no overflow on the mint supply. + destination_account.set_amount(destination_account.amount() + amount); } Ok(()) diff --git a/p-token/src/processor/shared/mod.rs b/p-token/src/processor/shared/mod.rs index e55f129..9569cdf 100644 --- a/p-token/src/processor/shared/mod.rs +++ b/p-token/src/processor/shared/mod.rs @@ -6,6 +6,7 @@ pub mod approve; pub mod burn; pub mod initialize_account; +pub mod initialize_mint; pub mod initialize_multisig; pub mod mint_to; pub mod toggle_account_state; diff --git a/p-token/src/processor/shared/toggle_account_state.rs b/p-token/src/processor/shared/toggle_account_state.rs index ba1b7aa..6683819 100644 --- a/p-token/src/processor/shared/toggle_account_state.rs +++ b/p-token/src/processor/shared/toggle_account_state.rs @@ -28,7 +28,9 @@ pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> P } // SAFETY: single immutable borrow of `mint_info` account data and - // `load` validates that the mint is initialized. + // `load` validates that the mint is initialized; additionally, an + // account cannot be both a token account and a mint, so if duplicates are + // passed in, one of them will fail the `load` check. let mint = unsafe { load::(mint_info.borrow_data_unchecked())? }; match mint.freeze_authority() { diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index 84ae7cf..2868678 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -64,6 +64,16 @@ pub fn process_transfer( // Implicitly validates that the account has enough tokens by calculating the // remaining amount - the amount is only updated on the account if the transfer // is successful. + // + // Note: the logic is partially duplicated for self transfers and transfers + // to different accounts to improve CU consumption: + // + // - self-transfer: we only need to check that the source account is not frozen + // and has enough tokens. + // + // - transfers to different accounts: we need to check that the source and + // destination accounts are not frozen, have the same mint, and the source + // account has enough tokens. let remaining_amount = if self_transfer { if source_account.is_frozen() { return Err(TokenError::AccountFrozen.into()); @@ -75,7 +85,8 @@ pub fn process_transfer( .ok_or(TokenError::InsufficientFunds)? } else { // SAFETY: scoped immutable borrow to `destination_account_info` account data and - // `load` validates that the account is initialized. + // `load` validates that the account is initialized; additionally, the account + // is guaranteed to be different than `source_account_info`. let destination_account = unsafe { load::(destination_account_info.borrow_data_unchecked())? }; @@ -143,15 +154,14 @@ pub fn process_transfer( source_account.set_amount(remaining_amount); // SAFETY: single mutable borrow to `destination_account_info` account data; the account - // is guaranteed to be initialized and different than `source_account_info`. + // is guaranteed to be initialized and different than `source_account_info`; it was + // also already validated to be a token account. let destination_account = unsafe { load_mut_unchecked::(destination_account_info.borrow_mut_data_unchecked())? }; - let destination_amount = destination_account - .amount() - .checked_add(amount) - .ok_or(TokenError::Overflow)?; - destination_account.set_amount(destination_amount); + // Note: The amount of a token account is always within the range of the + // mint supply (`u64`). + destination_account.set_amount(destination_account.amount() + amount); if source_account.is_native() { // SAFETY: single mutable borrow to `source_account_info` lamports. @@ -160,7 +170,8 @@ pub fn process_transfer( .checked_sub(amount) .ok_or(TokenError::Overflow)?; - // SAFETY: single mutable borrow to `destination_account_info` lamports. + // SAFETY: single mutable borrow to `destination_account_info` lamports; the account + // is already validated to be different from `source_account_info`. let destination_lamports = unsafe { destination_account_info.borrow_mut_lamports_unchecked() }; *destination_lamports = destination_lamports diff --git a/p-token/src/processor/transfer_checked.rs b/p-token/src/processor/transfer_checked.rs index ea75a28..b688cd4 100644 --- a/p-token/src/processor/transfer_checked.rs +++ b/p-token/src/processor/transfer_checked.rs @@ -11,16 +11,12 @@ pub fn process_transfer_checked( let (amount, decimals) = if instruction_data.len() == 9 { let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); ( - u64::from_le_bytes( - amount - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ), - decimals.first(), + u64::from_le_bytes(amount.try_into().unwrap()), + decimals.first().copied(), ) } else { return Err(ProgramError::InvalidInstructionData); }; - shared::transfer::process_transfer(accounts, amount, decimals.copied()) + shared::transfer::process_transfer(accounts, amount, decimals) } From baa5918cce8326e3f63f719868a938c43438750e Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Tue, 11 Mar 2025 14:21:24 +0000 Subject: [PATCH 318/335] p-token: Add `batch` instruction (#35) * Update workspace * Rename interface crate * Fix spelling * [wip]: Fix review comments * A few more fixes * Add batch instruction * Add test for batch * Clean up comments * Fix spelling * Fix merge * Remove test-sbf feature * Fix review comments --- interface/src/instruction.rs | 21 ++- p-token/Cargo.toml | 1 - p-token/src/entrypoint.rs | 140 +++++++++------- p-token/src/processor/batch.rs | 57 +++++++ p-token/src/processor/mod.rs | 2 + p-token/tests/amount_to_ui_amount.rs | 2 - p-token/tests/approve.rs | 2 - p-token/tests/approve_checked.rs | 2 - p-token/tests/batch.rs | 221 ++++++++++++++++++++++++++ p-token/tests/burn.rs | 2 - p-token/tests/burn_checked.rs | 2 - p-token/tests/close_account.rs | 2 - p-token/tests/freeze_account.rs | 2 - p-token/tests/initialize_account.rs | 2 - p-token/tests/initialize_account2.rs | 2 - p-token/tests/initialize_account3.rs | 2 - p-token/tests/initialize_mint.rs | 2 - p-token/tests/initialize_mint2.rs | 2 - p-token/tests/initialize_multisig.rs | 2 - p-token/tests/initialize_multisig2.rs | 2 - p-token/tests/mint_to.rs | 2 - p-token/tests/mint_to_checked.rs | 2 - p-token/tests/revoke.rs | 2 - p-token/tests/set_authority.rs | 2 - p-token/tests/thaw_account.rs | 2 - p-token/tests/transfer.rs | 2 - p-token/tests/transfer_checked.rs | 2 - p-token/tests/ui_amount_to_amount.rs | 2 - package.json | 2 +- 29 files changed, 383 insertions(+), 105 deletions(-) create mode 100644 p-token/src/processor/batch.rs create mode 100644 p-token/tests/batch.rs diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index e0f747e..6de462c 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -477,6 +477,24 @@ pub enum TokenInstruction { /// /// - `&str` The `ui_amount` of tokens to reformat. UiAmountToAmount, + + /// Executes a batch of instructions. The instructions to be executed are specified + /// in sequence on the instruction data. Each instruction provides: + /// - `u8`: number of accounts + /// - `u8`: instruction data length (includes the discriminator) + /// - `u8`: instruction discriminator + /// - `[u8]`: instruction data + /// + /// Accounts follow a similar pattern, where accounts for each instruction are + /// specified in sequence. Therefore, the number of accounts expected by this + /// instruction is variable, i.e., it depends on the instructions provided. + /// + /// Both the number of accounts and instruction data length are used to identify + /// the slice of accounts and instruction data for each instruction. + /// + /// Note that it is not sound to have a `batch` instruction that contains other + /// `batch` instruction; an error will be raised when this is detected. + Batch = 255, // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the // latter remains a superset of this instruction set. New variants also need to be added to // token/js/src/instructions/types.ts to maintain @solana/spl-token compatibility @@ -485,11 +503,10 @@ pub enum TokenInstruction { impl TryFrom for TokenInstruction { type Error = ProgramError; - #[inline(always)] fn try_from(value: u8) -> Result { match value { // SAFETY: `value` is guaranteed to be in the range of the enum variants. - 0..=24 => Ok(unsafe { core::mem::transmute::(value) }), + 0..=24 | 255 => Ok(unsafe { core::mem::transmute::(value) }), _ => Err(ProgramError::InvalidInstructionData), } } diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 63dfb31..d876998 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -13,7 +13,6 @@ crate-type = ["cdylib"] [features] logging = [] -test-sbf = [] [dependencies] pinocchio = { version = "0.7", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 80fd04e..4483f02 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -2,7 +2,6 @@ use pinocchio::{ account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint, program_error::ProgramError, pubkey::Pubkey, ProgramResult, }; -use spl_token_interface::instruction::TokenInstruction; use crate::processor::*; @@ -14,218 +13,245 @@ default_panic_handler!(); /// Process an instruction. /// +/// In the first stage, the entrypoint checks the discriminator of the instruction data +/// to determine whether the instruction is a "batch" instruction or a "regular" instruction. +/// This avoids nesting of "batch" instructions, since it is not sound to have a "batch" +/// instruction inside another "batch" instruction. +#[inline(always)] +pub fn process_instruction( + _program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + let [discriminator, remaining @ ..] = instruction_data else { + return Err(ProgramError::InvalidInstructionData); + }; + + if *discriminator == 255 { + // 255 - Batch + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: Batch"); + + return process_batch(accounts, remaining); + } + + inner_process_instruction(accounts, instruction_data) +} + +/// Process a "regular" instruction. +/// /// The processor of the token program is divided into two parts to reduce the overhead /// of having a large `match` statement. The first part of the processor handles the /// most common instructions, while the second part handles the remaining instructions. +/// /// The rationale is to reduce the overhead of making multiple comparisons for popular /// instructions. /// -/// Instructions on the first part of the processor: +/// Instructions on the first part of the inner processor: /// -/// - `0`: `InitializeMint` -/// - `3`: `Transfer` -/// - `7`: `MintTo` -/// - `9`: `CloseAccount` +/// - `0`: `InitializeMint` +/// - `1`: `InitializeAccount` +/// - `3`: `Transfer` +/// - `7`: `MintTo` +/// - `9`: `CloseAccount` +/// - `16`: `InitializeAccount2` /// - `18`: `InitializeAccount3` /// - `20`: `InitializeMint2` #[inline(always)] -pub fn process_instruction( - _program_id: &Pubkey, +pub(crate) fn inner_process_instruction( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let (discriminator, instruction_data) = instruction_data - .split_first() - .ok_or(ProgramError::InvalidInstructionData)?; - let instruction = TokenInstruction::try_from(*discriminator)?; + let [discriminator, instruction_data @ ..] = instruction_data else { + return Err(ProgramError::InvalidInstructionData); + }; - match instruction { + match *discriminator { // 0 - InitializeMint - TokenInstruction::InitializeMint => { + 0 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMint"); process_initialize_mint(accounts, instruction_data) } + // 1 - InitializeAccount + 1 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeAccount"); + process_initialize_account(accounts) + } // 3 - Transfer - TokenInstruction::Transfer => { + 3 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Transfer"); process_transfer(accounts, instruction_data) } // 7 - MintTo - TokenInstruction::MintTo => { + 7 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: MintTo"); process_mint_to(accounts, instruction_data) } // 9 - CloseAccount - TokenInstruction::CloseAccount => { + 9 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: CloseAccount"); process_close_account(accounts) } + // 16 - InitializeAccount2 + 16 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: InitializeAccount2"); + + process_initialize_account2(accounts, instruction_data) + } // 18 - InitializeAccount3 - TokenInstruction::InitializeAccount3 => { + 18 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeAccount3"); process_initialize_account3(accounts, instruction_data) } // 20 - InitializeMint2 - TokenInstruction::InitializeMint2 => { + 20 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMint2"); process_initialize_mint2(accounts, instruction_data) } - _ => process_remaining_instruction(accounts, instruction_data, instruction), + d => inner_process_remaining_instruction(accounts, instruction_data, d), } } -/// Process the remaining instructions. +/// Process a remaining "regular" instruction. /// -/// This function is called by the `process_instruction` function if the discriminator +/// This function is called by the [`inner_process_instruction`] function if the discriminator /// does not match any of the common instructions. This function is used to reduce the -/// overhead of having a large `match` statement in the `process_instruction` function. -fn process_remaining_instruction( +/// overhead of having a large `match` statement in the [`inner_process_instruction`] function. +fn inner_process_remaining_instruction( accounts: &[AccountInfo], instruction_data: &[u8], - instruction: TokenInstruction, + discriminator: u8, ) -> ProgramResult { - match instruction { - // 1 - InitializeAccount - TokenInstruction::InitializeAccount => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: InitializeAccount"); - - process_initialize_account(accounts) - } + match discriminator { // 2 - InitializeMultisig - TokenInstruction::InitializeMultisig => { + 2 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMultisig"); process_initialize_multisig(accounts, instruction_data) } // 4 - Approve - TokenInstruction::Approve => { + 4 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Approve"); process_approve(accounts, instruction_data) } // 5 - Revoke - TokenInstruction::Revoke => { + 5 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Revoke"); process_revoke(accounts, instruction_data) } // 6 - SetAuthority - TokenInstruction::SetAuthority => { + 6 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: SetAuthority"); process_set_authority(accounts, instruction_data) } // 8 - Burn - TokenInstruction::Burn => { + 8 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Burn"); process_burn(accounts, instruction_data) } // 10 - FreezeAccount - TokenInstruction::FreezeAccount => { + 10 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: FreezeAccount"); process_freeze_account(accounts) } // 11 - ThawAccount - TokenInstruction::ThawAccount => { + 11 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ThawAccount"); process_thaw_account(accounts) } // 12 - TransferChecked - TokenInstruction::TransferChecked => { + 12 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: TransferChecked"); process_transfer_checked(accounts, instruction_data) } // 13 - ApproveChecked - TokenInstruction::ApproveChecked => { + 13 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: ApproveChecked"); process_approve_checked(accounts, instruction_data) } // 14 - MintToChecked - TokenInstruction::MintToChecked => { + 14 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: MintToChecked"); process_mint_to_checked(accounts, instruction_data) } // 15 - BurnChecked - TokenInstruction::BurnChecked => { + 15 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: BurnChecked"); process_burn_checked(accounts, instruction_data) } - // 16 - InitializeAccount2 - TokenInstruction::InitializeAccount2 => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: InitializeAccount2"); - - process_initialize_account2(accounts, instruction_data) - } // 17 - SyncNative - TokenInstruction::SyncNative => { + 17 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: SyncNative"); process_sync_native(accounts) } // 19 - InitializeMultisig2 - TokenInstruction::InitializeMultisig2 => { + 19 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeMultisig2"); process_initialize_multisig2(accounts, instruction_data) } // 21 - GetAccountDataSize - TokenInstruction::GetAccountDataSize => { + 21 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: GetAccountDataSize"); process_get_account_data_size(accounts) } // 22 - InitializeImmutableOwner - TokenInstruction::InitializeImmutableOwner => { + 22 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: InitializeImmutableOwner"); process_initialize_immutable_owner(accounts) } // 23 - AmountToUiAmount - TokenInstruction::AmountToUiAmount => { + 23 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: AmountToUiAmount"); process_amount_to_ui_amount(accounts, instruction_data) } // 24 - UiAmountToAmount - TokenInstruction::UiAmountToAmount => { + 24 => { #[cfg(feature = "logging")] pinocchio::msg!("Instruction: UiAmountToAmount"); diff --git a/p-token/src/processor/batch.rs b/p-token/src/processor/batch.rs new file mode 100644 index 0000000..6c94208 --- /dev/null +++ b/p-token/src/processor/batch.rs @@ -0,0 +1,57 @@ +use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; + +use crate::entrypoint::inner_process_instruction; + +/// The size of the batch instruction header. +/// +/// The header of each instruction consists of two `u8` values: +/// * number of the accounts +/// * length of the instruction data +const IX_HEADER_SIZE: usize = 2; + +pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8]) -> ProgramResult { + loop { + // Validates the instruction data and accounts offset. + + if instruction_data.len() < IX_HEADER_SIZE { + // The instruction data must have at least two bytes. + return Err(ProgramError::InvalidInstructionData); + } + + // SAFETY: The instruction data is guaranteed to have at least two bytes (header) + // + one byte (discriminator). + let expected_accounts = unsafe { *instruction_data.get_unchecked(0) as usize }; + let data_offset = IX_HEADER_SIZE + unsafe { *instruction_data.get_unchecked(1) as usize }; + + if instruction_data.len() < data_offset || data_offset == IX_HEADER_SIZE { + return Err(ProgramError::InvalidInstructionData); + } + + if accounts.len() < expected_accounts { + return Err(ProgramError::NotEnoughAccountKeys); + } + + // Process the instruction. + + // SAFETY: The instruction data and accounts lengths are already validated so all + // slices are guaranteed to be valid. + let (ix_accounts, ix_data) = unsafe { + ( + accounts.get_unchecked(..expected_accounts), + instruction_data.get_unchecked(IX_HEADER_SIZE..data_offset), + ) + }; + + inner_process_instruction(ix_accounts, ix_data)?; + + if data_offset == instruction_data.len() { + // The batch is complete. + break; + } + + accounts = &accounts[expected_accounts..]; + instruction_data = &instruction_data[data_offset..]; + } + + Ok(()) +} diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 96e7586..0002c0f 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -16,6 +16,7 @@ use spl_token_interface::{ pub mod amount_to_ui_amount; pub mod approve; pub mod approve_checked; +pub mod batch; pub mod burn; pub mod burn_checked; pub mod close_account; @@ -44,6 +45,7 @@ pub mod shared; pub use amount_to_ui_amount::process_amount_to_ui_amount; pub use approve::process_approve; pub use approve_checked::process_approve_checked; +pub use batch::process_batch; pub use burn::process_burn; pub use burn_checked::process_burn_checked; pub use close_account::process_close_account; diff --git a/p-token/tests/amount_to_ui_amount.rs b/p-token/tests/amount_to_ui_amount.rs index b9d7079..a8de531 100644 --- a/p-token/tests/amount_to_ui_amount.rs +++ b/p-token/tests/amount_to_ui_amount.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/approve.rs b/p-token/tests/approve.rs index b47baa7..dbc606a 100644 --- a/p-token/tests/approve.rs +++ b/p-token/tests/approve.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs index 43c4837..3fb7c75 100644 --- a/p-token/tests/approve_checked.rs +++ b/p-token/tests/approve_checked.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/batch.rs b/p-token/tests/batch.rs new file mode 100644 index 0000000..f2cc481 --- /dev/null +++ b/p-token/tests/batch.rs @@ -0,0 +1,221 @@ +mod setup; + +use crate::setup::TOKEN_PROGRAM_ID; +use solana_program_test::{tokio, ProgramTest}; +use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, +}; + +fn batch_instruction(instructions: Vec) -> Result { + // Create a `Vec` of ordered `AccountMeta`s + let mut accounts: Vec = vec![]; + // Start with the batch discriminator + let mut data: Vec = vec![0xff]; + + for instruction in instructions { + // Error out on non-token IX. + if instruction.program_id.ne(&spl_token::ID) { + return Err(ProgramError::IncorrectProgramId); + } + + data.push(instruction.accounts.len() as u8); + data.push(instruction.data.len() as u8); + + data.extend_from_slice(&instruction.data); + accounts.extend_from_slice(&instruction.accounts); + } + + Ok(Instruction { + program_id: spl_token::ID, + data, + accounts, + }) +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn batch(token_program: Pubkey) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let rent = context.banks_client.get_rent().await.unwrap(); + + let mint_len = spl_token::state::Mint::LEN; + let mint_rent = rent.minimum_balance(mint_len); + + let account_len = spl_token::state::Account::LEN; + let account_rent = rent.minimum_balance(account_len); + + // Create a mint + let mint_a = Keypair::new(); + let mint_authority = Keypair::new(); + let create_mint_a = system_instruction::create_account( + &context.payer.pubkey(), + &mint_a.pubkey(), + mint_rent, + mint_len as u64, + &token_program, + ); + let initialize_mint_ix = spl_token::instruction::initialize_mint( + &token_program, + &mint_a.pubkey(), + &mint_authority.pubkey(), + None, + 6, + ) + .unwrap(); + + // Create a mint 2 with a freeze authority + let mint_b = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + let create_mint_b = system_instruction::create_account( + &context.payer.pubkey(), + &mint_b.pubkey(), + mint_rent, + mint_len as u64, + &token_program, + ); + let initialize_mint_with_freeze_authority_ix = spl_token::instruction::initialize_mint2( + &token_program, + &mint_b.pubkey(), + &mint_authority.pubkey(), + Some(&freeze_authority), + 6, + ) + .unwrap(); + + // Create 2 token accounts for mint A and 1 for mint B + let owner_a = Keypair::new(); + let owner_b = Keypair::new(); + let owner_a_ta_a = Keypair::new(); + let owner_b_ta_a = Keypair::new(); + + let create_owner_a_ta_a = system_instruction::create_account( + &context.payer.pubkey(), + &owner_a_ta_a.pubkey(), + account_rent, + account_len as u64, + &token_program, + ); + let create_owner_b_ta_a = system_instruction::create_account( + &context.payer.pubkey(), + &owner_b_ta_a.pubkey(), + account_rent, + account_len as u64, + &token_program, + ); + let intialize_owner_a_ta_a = spl_token::instruction::initialize_account3( + &token_program, + &owner_a_ta_a.pubkey(), + &mint_a.pubkey(), + &owner_a.pubkey(), + ) + .unwrap(); + let intialize_owner_b_ta_a = spl_token::instruction::initialize_account3( + &token_program, + &owner_b_ta_a.pubkey(), + &mint_a.pubkey(), + &owner_b.pubkey(), + ) + .unwrap(); + + // Mint Token A to Owner A + let mint_token_a_to_owner_a = spl_token::instruction::mint_to( + &token_program, + &mint_a.pubkey(), + &owner_a_ta_a.pubkey(), + &mint_authority.pubkey(), + &[], + 1_000_000, + ) + .unwrap(); + + // Transfer Token A from Owner A to Owner B + let transfer_token_a_to_owner_b = spl_token::instruction::transfer( + &token_program, + &owner_a_ta_a.pubkey(), + &owner_b_ta_a.pubkey(), + &owner_a.pubkey(), + &[], + 1_000_000, + ) + .unwrap(); + + // Close Token A + let close_owner_a_ta_a = spl_token::instruction::close_account( + &token_program, + &owner_a_ta_a.pubkey(), + &owner_a.pubkey(), + &owner_a.pubkey(), + &[], + ) + .unwrap(); + + let batch_ix = batch_instruction(vec![ + initialize_mint_ix, + initialize_mint_with_freeze_authority_ix, + intialize_owner_a_ta_a, + intialize_owner_b_ta_a, + mint_token_a_to_owner_a, + transfer_token_a_to_owner_b, + close_owner_a_ta_a, + ]) + .unwrap(); + + let tx = Transaction::new_signed_with_payer( + &[ + create_mint_a, + create_mint_b, + create_owner_a_ta_a, + create_owner_b_ta_a, + batch_ix, + ], + Some(&context.payer.pubkey()), + &vec![ + &context.payer, + &mint_a, + &mint_b, + &owner_a_ta_a, + &owner_b_ta_a, + &mint_authority, + &owner_a, + ], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let mint_a_account = context + .banks_client + .get_account(mint_a.pubkey()) + .await + .unwrap(); + assert!(mint_a_account.is_some()); + let mint_a_account = spl_token::state::Mint::unpack(&mint_a_account.unwrap().data).unwrap(); + assert_eq!(mint_a_account.supply, 1000000); + + let mint_b_account = context + .banks_client + .get_account(mint_b.pubkey()) + .await + .unwrap(); + assert!(mint_b_account.is_some()); + let mint_b_account = spl_token::state::Mint::unpack(&mint_b_account.unwrap().data).unwrap(); + assert_eq!(mint_b_account.supply, 0); + + let owner_b_ta_a_account = context + .banks_client + .get_account(owner_b_ta_a.pubkey()) + .await + .unwrap(); + assert!(owner_b_ta_a_account.is_some()); + let owner_b_ta_a_account = + spl_token::state::Account::unpack(&owner_b_ta_a_account.unwrap().data).unwrap(); + assert_eq!(owner_b_ta_a_account.amount, 1000000); +} diff --git a/p-token/tests/burn.rs b/p-token/tests/burn.rs index df6645d..67ffb90 100644 --- a/p-token/tests/burn.rs +++ b/p-token/tests/burn.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/burn_checked.rs b/p-token/tests/burn_checked.rs index c2256fd..a28a8b1 100644 --- a/p-token/tests/burn_checked.rs +++ b/p-token/tests/burn_checked.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/close_account.rs b/p-token/tests/close_account.rs index d4ece1c..b9ca15a 100644 --- a/p-token/tests/close_account.rs +++ b/p-token/tests/close_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/freeze_account.rs b/p-token/tests/freeze_account.rs index 2f34b18..0e8c498 100644 --- a/p-token/tests/freeze_account.rs +++ b/p-token/tests/freeze_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs index 17a2c11..0980b97 100644 --- a/p-token/tests/initialize_account.rs +++ b/p-token/tests/initialize_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/initialize_account2.rs b/p-token/tests/initialize_account2.rs index 2ec0805..0e91266 100644 --- a/p-token/tests/initialize_account2.rs +++ b/p-token/tests/initialize_account2.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/initialize_account3.rs b/p-token/tests/initialize_account3.rs index c418fc0..a2349aa 100644 --- a/p-token/tests/initialize_account3.rs +++ b/p-token/tests/initialize_account3.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 94406bd..4a761a2 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use std::mem::size_of; diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index 04ce4d4..7cf32c5 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use std::mem::size_of; diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 13a518d..9715545 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::TOKEN_PROGRAM_ID; diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index 40cf084..d380b3c 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::TOKEN_PROGRAM_ID; diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index 75626cb..96722ac 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs index 56fab40..f80bd35 100644 --- a/p-token/tests/mint_to_checked.rs +++ b/p-token/tests/mint_to_checked.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/revoke.rs b/p-token/tests/revoke.rs index 9ba9c7f..2be0ba2 100644 --- a/p-token/tests/revoke.rs +++ b/p-token/tests/revoke.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/set_authority.rs b/p-token/tests/set_authority.rs index 8d3f422..2b50005 100644 --- a/p-token/tests/set_authority.rs +++ b/p-token/tests/set_authority.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/thaw_account.rs b/p-token/tests/thaw_account.rs index 4d7f957..b00506a 100644 --- a/p-token/tests/thaw_account.rs +++ b/p-token/tests/thaw_account.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index 357ccb6..e2bd377 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs index 080bc77..b599946 100644 --- a/p-token/tests/transfer_checked.rs +++ b/p-token/tests/transfer_checked.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{account, mint, TOKEN_PROGRAM_ID}; diff --git a/p-token/tests/ui_amount_to_amount.rs b/p-token/tests/ui_amount_to_amount.rs index 37a8788..3e4754c 100644 --- a/p-token/tests/ui_amount_to_amount.rs +++ b/p-token/tests/ui_amount_to_amount.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "test-sbf")] - mod setup; use setup::{mint, TOKEN_PROGRAM_ID}; diff --git a/package.json b/package.json index 77a5526..dfcd107 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "rust:publish": "zx ./scripts/rust/publish.mjs", "rust:semver": "cargo semver-checks", "p-token:build": "zx ./scripts/rust/build-sbf.mjs p-token", - "p-token:test": "zx ./scripts/rust/test-sbf.mjs p-token" + "p-token:test": "zx ./scripts/rust/test.mjs p-token" }, "devDependencies": { "@codama/renderers-js": "^1.2.7", From 90152b12d0993a0052bcff169405de56c7d63c1d Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Tue, 11 Mar 2025 17:41:56 +0000 Subject: [PATCH 319/335] p-token: Add `withdraw_excess_lamports` instruction (#36) * Update workspace * Rename interface crate * Fix spelling * [wip]: Fix review comments * A few more fixes * Fix merge * Update workspace * Rename interface crate * Fix spelling * [wip]: Fix review comments * Add withdraw_excess_lamports instruction * Add test * Add missing safety comments * Add more tests * Fix merge * Use assert_matches --- Cargo.lock | 301 +++++++ interface/src/instruction.rs | 14 +- p-token/Cargo.toml | 2 + p-token/src/entrypoint.rs | 7 + p-token/src/processor/mod.rs | 2 + .../src/processor/withdraw_excess_lamports.rs | 80 ++ p-token/tests/withdraw_excess_lamports.rs | 756 ++++++++++++++++++ 7 files changed, 1161 insertions(+), 1 deletion(-) create mode 100644 p-token/src/processor/withdraw_excess_lamports.rs create mode 100644 p-token/tests/withdraw_excess_lamports.rs diff --git a/Cargo.lock b/Cargo.lock index f30c2e0..bcdc955 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2840,11 +2840,13 @@ name = "pinocchio-token-program" version = "0.0.0" dependencies = [ "assert_matches", + "num-traits", "pinocchio", "pinocchio-log", "solana-program-test", "solana-sdk", "spl-token 4.0.2", + "spl-token-2022", "spl-token-interface", "test-case", ] @@ -5861,6 +5863,12 @@ dependencies = [ "solana-sdk-ids", ] +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + [[package]] name = "solana-seed-derivable" version = "2.2.1" @@ -6736,6 +6744,136 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spl-discriminator" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7398da23554a31660f17718164e31d31900956054f54f52d5ec1be51cb4f4b3" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.96", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.96", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce0f668975d2b0536e8a8fd60e56a05c467f06021dae037f1d0cfed0de2e231d" +dependencies = [ + "bytemuck", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", +] + +[[package]] +name = "spl-memo" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f09647c0974e33366efeb83b8e2daebb329f0420149e74d3a4bd2c08cf9f7cb" +dependencies = [ + "solana-account-info", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "spl-pod" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a7d5950993e1ff2680bd989df298eeb169367fb2f9deeef1f132de6e4e8016" +dependencies = [ + "borsh 1.5.5", + "bytemuck", + "bytemuck_derive", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "solana-program-option", + "solana-pubkey", + "solana-zk-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-program-error" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" +dependencies = [ + "num-derive", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.96", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd99ff1e9ed2ab86e3fd582850d47a739fec1be9f4661cba1782d3a0f26805f3" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", + "thiserror 1.0.69", +] + [[package]] name = "spl-token" version = "4.0.2" @@ -6784,6 +6922,105 @@ dependencies = [ "thiserror 2.0.11", ] +[[package]] +name = "spl-token" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-2022" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9048b26b0df0290f929ff91317c83db28b3ef99af2b3493dd35baa146774924c" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "solana-security-txt", + "solana-zk-sdk", + "spl-elgamal-registry", + "spl-memo", + "spl-pod", + "spl-token 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", + "thiserror 2.0.11", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170378693c5516090f6d37ae9bad2b9b6125069be68d9acd4865bbe9fc8499fd" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff2d6a445a147c9d6dd77b8301b1e116c8299601794b558eafa409b342faf96" +dependencies = [ + "bytemuck", + "solana-curve25519", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.11", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e3597628b0d2fe94e7900fd17cdb4cfbb31ee35c66f82809d27d86e44b2848b" +dependencies = [ + "curve25519-dalek 4.1.3", + "solana-zk-sdk", + "thiserror 2.0.11", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d595667ed72dbfed8c251708f406d7c2814a3fa6879893b323d56a10bedfc799" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + [[package]] name = "spl-token-interface" version = "0.0.0" @@ -6794,6 +7031,70 @@ dependencies = [ "strum_macros 0.27.1", ] +[[package]] +name = "spl-token-metadata-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" +dependencies = [ + "borsh 1.5.5", + "num-derive", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-type-length-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index 6de462c..5b7b0ea 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -478,6 +478,18 @@ pub enum TokenInstruction { /// - `&str` The `ui_amount` of tokens to reformat. UiAmountToAmount, + /// This instruction is to be used to rescue SOL sent to any `TokenProgram` + /// owned account by sending them to any other account, leaving behind only + /// lamports for rent exemption. + /// + /// Accounts expected by this instruction: + /// + /// 0. `[writable]` Source Account owned by the token program + /// 1. `[writable]` Destination account + /// 2. `[signer]` Authority + /// 3. `..+M` `[signer]` M signer accounts. + WithdrawExcessLamports = 38, + /// Executes a batch of instructions. The instructions to be executed are specified /// in sequence on the instruction data. Each instruction provides: /// - `u8`: number of accounts @@ -506,7 +518,7 @@ impl TryFrom for TokenInstruction { fn try_from(value: u8) -> Result { match value { // SAFETY: `value` is guaranteed to be in the range of the enum variants. - 0..=24 | 255 => Ok(unsafe { core::mem::transmute::(value) }), + 0..=24 | 38 | 255 => Ok(unsafe { core::mem::transmute::(value) }), _ => Err(ProgramError::InvalidInstructionData), } } diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index d876998..03d6189 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -21,7 +21,9 @@ spl-token-interface = { version = "^0", path = "../interface" } [dev-dependencies] assert_matches = "1.5.0" +num-traits = "0.2" solana-program-test = "2.1" solana-sdk = "2.1" spl-token = { version="^4", features=["no-entrypoint"] } +spl-token-2022 = { version="^7", features=["no-entrypoint"] } test-case = "3.3.1" diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 4483f02..0296dd9 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -257,6 +257,13 @@ fn inner_process_remaining_instruction( process_ui_amount_to_amount(accounts, instruction_data) } + // 38 - WithdrawExcessLamports + 38 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: WithdrawExcessLamports"); + + process_withdraw_excess_lamports(accounts) + } _ => Err(ProgramError::InvalidInstructionData), } } diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 0002c0f..5182e83 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -39,6 +39,7 @@ pub mod thaw_account; pub mod transfer; pub mod transfer_checked; pub mod ui_amount_to_amount; +pub mod withdraw_excess_lamports; // Shared processors. pub mod shared; @@ -68,6 +69,7 @@ pub use thaw_account::process_thaw_account; pub use transfer::process_transfer; pub use transfer_checked::process_transfer_checked; pub use ui_amount_to_amount::process_ui_amount_to_amount; +pub use withdraw_excess_lamports::process_withdraw_excess_lamports; /// Maximum number of digits in a formatted `u64`. /// diff --git a/p-token/src/processor/withdraw_excess_lamports.rs b/p-token/src/processor/withdraw_excess_lamports.rs new file mode 100644 index 0000000..44e9015 --- /dev/null +++ b/p-token/src/processor/withdraw_excess_lamports.rs @@ -0,0 +1,80 @@ +use pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, +}; +use spl_token_interface::{ + error::TokenError, + state::{account::Account, load, mint::Mint, multisig::Multisig, Transmutable}, +}; + +use super::validate_owner; + +#[inline(always)] +pub fn process_withdraw_excess_lamports(accounts: &[AccountInfo]) -> ProgramResult { + let [source_account_info, destination_info, authority_info, remaining @ ..] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + // SAFETY: single mutable borrow to `source_account_info` account data + let source_data = unsafe { source_account_info.borrow_data_unchecked() }; + + match source_data.len() { + Account::LEN => { + // SAFETY: `source_data` has the same length as `Account`. + let account = unsafe { load::(source_data)? }; + + if account.is_native() { + return Err(TokenError::NativeNotSupported.into()); + } + + validate_owner(&account.owner, authority_info, remaining)?; + } + Mint::LEN => { + // SAFETY: `source_data` has the same length as `Mint`. + let mint = unsafe { load::(source_data)? }; + + if let Some(mint_authority) = mint.mint_authority() { + validate_owner(mint_authority, authority_info, remaining)?; + } else { + return Err(TokenError::AuthorityTypeNotSupported.into()); + } + } + Multisig::LEN => { + validate_owner(source_account_info.key(), authority_info, remaining)?; + } + _ => return Err(TokenError::InvalidState.into()), + } + + // Withdraws the excess lamports from the source account. + + let source_rent_exempt_reserve = Rent::get()?.minimum_balance(source_data.len()); + + let transfer_amount = source_account_info + .lamports() + .checked_sub(source_rent_exempt_reserve) + .ok_or(TokenError::NotRentExempt)?; + + let source_starting_lamports = source_account_info.lamports(); + // SAFETY: single mutable borrow to `source_account_info` lamports. + unsafe { + // Moves the lamports out of the source account. + // + // Note: The `transfer_amount` is guaranteed to be less than the source account's + // lamports. + *source_account_info.borrow_mut_lamports_unchecked() = + source_starting_lamports - transfer_amount; + } + + let destination_starting_lamports = destination_info.lamports(); + // SAFETY: single mutable borrow to `destination_info` lamports. + unsafe { + // Moves the lamports to the destination account. + *destination_info.borrow_mut_lamports_unchecked() = destination_starting_lamports + .checked_add(transfer_amount) + .ok_or(TokenError::Overflow)?; + } + + Ok(()) +} diff --git a/p-token/tests/withdraw_excess_lamports.rs b/p-token/tests/withdraw_excess_lamports.rs new file mode 100644 index 0000000..6e56c0c --- /dev/null +++ b/p-token/tests/withdraw_excess_lamports.rs @@ -0,0 +1,756 @@ +mod setup; + +use assert_matches::assert_matches; +use setup::{mint, TOKEN_PROGRAM_ID}; +use solana_program_test::{tokio, BanksClientError, ProgramTest}; +use solana_sdk::{ + instruction::InstructionError, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::{Transaction, TransactionError}, +}; +use spl_token_interface::state::{account::Account, mint::Mint, multisig::Multisig}; +use std::mem::size_of; + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn withdraw_excess_lamports_from_mint(token_program: Pubkey) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given a mint authority, freeze authority and an account keypair. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + let account = Keypair::new(); + let account_pubkey = account.pubkey(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_mint( + &spl_token::ID, + &account.pubkey(), + &mint_authority.pubkey(), + Some(&freeze_authority), + 0, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // And we initialize a mint account with excess lamports. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // When we withdraw the excess lamports. + + let destination = Pubkey::new_unique(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &account_pubkey, + &destination, + &mint_authority.pubkey(), + &[], + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &mint_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the destination account has the excess lamports. + + let destination = context.banks_client.get_account(destination).await.unwrap(); + + assert!(destination.is_some()); + + let destination = destination.unwrap(); + assert_eq!(destination.lamports, excess_lamports); +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn withdraw_excess_lamports_from_account(token_program: Pubkey) { + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given a mint account. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority, + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // Given a mint authority, freeze authority and an account keypair. + + let owner = Keypair::new(); + let account = Keypair::new(); + let account_pubkey = account.pubkey(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_account( + &spl_token::ID, + &account.pubkey(), + &mint, + &owner.pubkey(), + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new mint account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // When we withdraw the excess lamports. + + let destination = Pubkey::new_unique(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &account_pubkey, + &destination, + &owner.pubkey(), + &[], + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the destination account has the excess lamports. + + let destination = context.banks_client.get_account(destination).await.unwrap(); + + assert!(destination.is_some()); + + let destination = destination.unwrap(); + assert_eq!(destination.lamports, excess_lamports); +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn withdraw_excess_lamports_from_multisig(token_program: Pubkey) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given an account + + let multisig = Keypair::new(); + let signer1 = Keypair::new(); + let signer1_pubkey = signer1.pubkey(); + let signer2 = Keypair::new(); + let signer2_pubkey = signer2.pubkey(); + let signer3 = Keypair::new(); + let signer3_pubkey = signer3.pubkey(); + let signers = vec![&signer1_pubkey, &signer2_pubkey, &signer3_pubkey]; + + let rent = context.banks_client.get_rent().await.unwrap(); + let account_size = size_of::(); + + let mut initialize_ix = spl_token::instruction::initialize_multisig( + &spl_token::ID, + &multisig.pubkey(), + &signers, + 3, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // And we initialize the multisig account. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &multisig.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &multisig], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(multisig.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // When we withdraw the excess lamports. + + let destination = Pubkey::new_unique(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &multisig.pubkey(), + &destination, + &multisig.pubkey(), + &signers, + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &signer1, &signer2, &signer3], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the destination account has the excess lamports. + + let destination = context.banks_client.get_account(destination).await.unwrap(); + + assert!(destination.is_some()); + + let destination = destination.unwrap(); + assert_eq!(destination.lamports, excess_lamports); +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn fail_withdraw_excess_lamports_from_mint_wrong_authority(token_program: Pubkey) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given a mint authority, freeze authority and an account keypair. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + let account = Keypair::new(); + let account_pubkey = account.pubkey(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_mint( + &spl_token::ID, + &account.pubkey(), + &mint_authority.pubkey(), + Some(&freeze_authority), + 0, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // And we initialize a mint account with excess lamports. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // When we try to withdraw the excess lamports with the wrong authority. + + let destination = Pubkey::new_unique(); + let wrong_authority = Keypair::new(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &account_pubkey, + &destination, + &wrong_authority.pubkey(), + &[], + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &wrong_authority], + context.last_blockhash, + ); + let error = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err(); + + // The we expect an error. + + assert_matches!( + error, + BanksClientError::TransactionError(TransactionError::InstructionError( + _, + InstructionError::Custom(4) // TokenError::OwnerMismatch + )) + ); +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn fail_withdraw_excess_lamports_from_account_wrong_authority(token_program: Pubkey) { + let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given a mint account. + + let mint_authority = Pubkey::new_unique(); + let freeze_authority = Pubkey::new_unique(); + + let mint = mint::initialize( + &mut context, + mint_authority, + Some(freeze_authority), + &token_program, + ) + .await + .unwrap(); + + // Given a mint authority, freeze authority and an account keypair. + + let owner = Keypair::new(); + let account = Keypair::new(); + let account_pubkey = account.pubkey(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_account( + &spl_token::ID, + &account.pubkey(), + &mint, + &owner.pubkey(), + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // When a new mint account is created and initialized. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &account.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // When we try to withdraw the excess lamports with the wrong owner. + + let destination = Pubkey::new_unique(); + let wrong_owner = Keypair::new(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &account_pubkey, + &destination, + &wrong_owner.pubkey(), + &[], + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &wrong_owner], + context.last_blockhash, + ); + let error = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err(); + + // The we expect an error. + + assert_matches!( + error, + BanksClientError::TransactionError(TransactionError::InstructionError( + _, + InstructionError::Custom(4) // TokenError::OwnerMismatch + )) + ); +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn fail_withdraw_excess_lamports_from_multisig_wrong_authority(token_program: Pubkey) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given an account + + let multisig = Keypair::new(); + let signer1 = Keypair::new(); + let signer1_pubkey = signer1.pubkey(); + let signer2 = Keypair::new(); + let signer2_pubkey = signer2.pubkey(); + let signer3 = Keypair::new(); + let signer3_pubkey = signer3.pubkey(); + let signers = vec![&signer1_pubkey, &signer2_pubkey, &signer3_pubkey]; + + let rent = context.banks_client.get_rent().await.unwrap(); + let account_size = size_of::(); + + let mut initialize_ix = spl_token::instruction::initialize_multisig( + &spl_token::ID, + &multisig.pubkey(), + &signers, + 3, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // And we initialize the multisig account. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &multisig.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &multisig], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(multisig.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // When we try to withdraw the excess lamports with the wrong authority. + + let destination = Pubkey::new_unique(); + let wrong_authority = Keypair::new(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &multisig.pubkey(), + &destination, + &wrong_authority.pubkey(), + &signers, + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &signer1, &signer2, &signer3], + context.last_blockhash, + ); + let error = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err(); + + // The we expect an error. + + assert_matches!( + error, + BanksClientError::TransactionError(TransactionError::InstructionError( + _, + InstructionError::Custom(4) // TokenError::OwnerMismatch + )) + ); +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn fail_withdraw_excess_lamports_from_multisig_missing_signer(token_program: Pubkey) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given an account + + let multisig = Keypair::new(); + let signer1 = Keypair::new(); + let signer1_pubkey = signer1.pubkey(); + let signer2 = Keypair::new(); + let signer2_pubkey = signer2.pubkey(); + let signer3 = Keypair::new(); + let signer3_pubkey = signer3.pubkey(); + let signers = vec![&signer1_pubkey, &signer2_pubkey, &signer3_pubkey]; + + let rent = context.banks_client.get_rent().await.unwrap(); + let account_size = size_of::(); + + let mut initialize_ix = spl_token::instruction::initialize_multisig( + &spl_token::ID, + &multisig.pubkey(), + &signers, + 3, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // And we initialize the multisig account. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &multisig.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &multisig], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(multisig.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // When we try to withdraw the excess lamports with the wrong authority. + + let destination = Pubkey::new_unique(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &multisig.pubkey(), + &destination, + &multisig.pubkey(), + &[&signer1_pubkey, &signer2_pubkey], + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &signer1, &signer2], + context.last_blockhash, + ); + let error = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err(); + + // The we expect an error. + + assert_matches!( + error, + BanksClientError::TransactionError(TransactionError::InstructionError( + _, + InstructionError::MissingRequiredSignature + )) + ); +} From da8d9bd36474dd4e341943861ad6988f516e3a57 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Fri, 14 Mar 2025 16:37:00 +0000 Subject: [PATCH 320/335] p-token: Add `spl-token` test fixtures (#39) * Remove unusual test * Add fixtures test script * Install solana on fixtures workflow * Fix review comments --- .github/workflows/main.yml | 60 +++++++++++++++++++++++++++++++++++++ package.json | 5 +++- program/tests/processor.rs | 26 ---------------- scripts/rust/fixtures.mjs | 61 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 27 deletions(-) create mode 100644 scripts/rust/fixtures.mjs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 52cfd07..9b3c962 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -151,6 +151,35 @@ jobs: path: ./**/*.so key: ${{ runner.os }}-builds-${{ github.sha }} + build_ptoken: + name: Build p-token + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-build-program + solana: true + + - name: Build + run: pnpm p-token:build + + - name: Upload p-token Builds + uses: actions/upload-artifact@v4 + with: + name: p-token-builds + path: ./target/deploy/*.so + if-no-files-found: error + + - name: Save p-token Build For Client Jobs + uses: actions/cache/save@v4 + with: + path: ./**/*.so + key: ${{ runner.os }}-ptoken-build-${{ github.sha }} + test_client_js: name: Test Client JS runs-on: ubuntu-latest @@ -212,3 +241,34 @@ jobs: - name: Test run: pnpm programs:test + + conformance_ptoken: + name: Conformance Test for p-token + runs-on: ubuntu-latest + needs: build_ptoken + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-fixtures-ptoken + solana: true + + - name: Restore Program Builds + uses: actions/cache/restore@v4 + with: + path: ./**/*.so + key: ${{ runner.os }}-ptoken-build-${{ github.sha }} + + - name: Install mollusk-svm-cli + uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: mollusk-svm-cli + + - name: Generate SPL Token Fixtures + run: pnpm fixtures:generate + + - name: Run Fixtures + run: pnpm fixtures:run pinocchio_token_program diff --git a/package.json b/package.json index dfcd107..e336c22 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,10 @@ "rust:publish": "zx ./scripts/rust/publish.mjs", "rust:semver": "cargo semver-checks", "p-token:build": "zx ./scripts/rust/build-sbf.mjs p-token", - "p-token:test": "zx ./scripts/rust/test.mjs p-token" + "p-token:test": "zx ./scripts/rust/test.mjs p-token", + "fixtures:clean": "zx ./scripts/rust/fixtures.mjs clean", + "fixtures:generate": "zx ./scripts/rust/fixtures.mjs generate", + "fixtures:run": "zx ./scripts/rust/fixtures.mjs run" }, "devDependencies": { "@codama/renderers-js": "^1.2.7", diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 025577a..7466e55 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -5366,32 +5366,6 @@ fn test_overflow() { .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX); - - // manipulate account balance to attempt overflow transfer - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.amount = 1; - Account::pack(account, &mut account2_account.data).unwrap(); - - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner2_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner2_account, - ], - &[Check::err(TokenError::Overflow.into())], - ) - ); } #[test] diff --git a/scripts/rust/fixtures.mjs b/scripts/rust/fixtures.mjs new file mode 100644 index 0000000..7ea6158 --- /dev/null +++ b/scripts/rust/fixtures.mjs @@ -0,0 +1,61 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { existsSync } from 'fs'; +import { cliArguments, workingDirectory } from '../utils.mjs'; + +// Directory where the fixtures are generated. +const FIXTURES_DIR = path.join(workingDirectory, 'target', 'fixtures'); +// Directory of the SPL Token program. +const SPL_TOKEN_DIR = path.join(workingDirectory, 'program'); +// Directory of the SBF program. +const SBF_OUTPUT_DIR = path.join(workingDirectory, 'target', 'deploy'); + +const [command, ...args] = cliArguments(); + +switch (command) { + case 'clean': + await clean(); + break; + case 'generate': + await generate(); + break; + case 'run': + await run(args); + break; + default: + throw new Error(`Unknown command: ${command}`); +} + +async function clean() { + await $`rm -rf ${FIXTURES_DIR}`; +} + +async function generate() { + if (existsSync(FIXTURES_DIR)) { + echo(chalk.yellow('[ WARNING ]'), `Fixtures directory already exists.`); + } else { + await $`mkdir ${FIXTURES_DIR}`; + + // Fixtures are generated from the SPL Token program. + cd(SPL_TOKEN_DIR); + + await $`RUST_LOG=error EJECT_FUZZ_FIXTURES=${FIXTURES_DIR} cargo test-sbf --features mollusk-svm/fuzz`; + } +} + +async function run(args) { + if (!existsSync(FIXTURES_DIR)) { + throw new Error(`Fixtures directory does not exist: ${FIXTURES_DIR}`); + } + + const [programName] = args; + if (!programName) { + throw new Error('The name of the program file must be provided.'); + } + + await $`mollusk execute-fixture \ + ${path.join(SBF_OUTPUT_DIR, programName + '.so')} \ + ${FIXTURES_DIR} \ + TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA \ + --ignore-compute-units`; +} From 261bbdd1aa5c697e54f9cd012bf5da331efbf7ad Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Fri, 14 Mar 2025 16:45:46 +0000 Subject: [PATCH 321/335] p-token: Add format and lint scripts (#40) * Fix formatting * Fix clippy * Add format and lint scripts * Tweak jobs order --- .github/workflows/main.yml | 39 +++++++++ Cargo.toml | 2 +- interface/src/instruction.rs | 66 +++++++++------ interface/src/state/account.rs | 7 +- interface/src/state/mint.rs | 7 +- interface/src/state/mod.rs | 5 +- interface/src/state/multisig.rs | 10 ++- p-token/Cargo.toml | 3 + p-token/src/entrypoint.rs | 48 ++++++----- p-token/src/processor/amount_to_ui_amount.rs | 22 ++--- p-token/src/processor/approve.rs | 7 +- p-token/src/processor/approve_checked.rs | 7 +- p-token/src/processor/batch.rs | 17 ++-- p-token/src/processor/burn.rs | 7 +- p-token/src/processor/burn_checked.rs | 7 +- p-token/src/processor/close_account.rs | 17 ++-- p-token/src/processor/freeze_account.rs | 7 +- .../src/processor/get_account_data_size.rs | 18 ++-- p-token/src/processor/initialize_account.rs | 7 +- p-token/src/processor/initialize_account2.rs | 9 +- p-token/src/processor/initialize_account3.rs | 9 +- .../processor/initialize_immutable_owner.rs | 10 ++- p-token/src/processor/initialize_mint.rs | 7 +- p-token/src/processor/initialize_mint2.rs | 7 +- p-token/src/processor/initialize_multisig.rs | 7 +- p-token/src/processor/initialize_multisig2.rs | 7 +- p-token/src/processor/mint_to.rs | 7 +- p-token/src/processor/mint_to_checked.rs | 7 +- p-token/src/processor/mod.rs | 82 +++++++++---------- p-token/src/processor/revoke.rs | 13 +-- p-token/src/processor/set_authority.rs | 19 +++-- p-token/src/processor/shared/approve.rs | 17 ++-- p-token/src/processor/shared/burn.rs | 13 +-- .../processor/shared/initialize_account.rs | 36 ++++---- .../src/processor/shared/initialize_mint.rs | 28 ++++--- .../processor/shared/initialize_multisig.rs | 24 +++--- p-token/src/processor/shared/mint_to.rs | 14 ++-- .../processor/shared/toggle_account_state.rs | 13 +-- p-token/src/processor/shared/transfer.rs | 40 +++++---- p-token/src/processor/sync_native.rs | 13 +-- p-token/src/processor/thaw_account.rs | 7 +- p-token/src/processor/transfer.rs | 7 +- p-token/src/processor/transfer_checked.rs | 7 +- p-token/src/processor/ui_amount_to_amount.rs | 20 +++-- .../src/processor/withdraw_excess_lamports.rs | 28 ++++--- p-token/tests/amount_to_ui_amount.rs | 8 +- p-token/tests/approve.rs | 16 ++-- p-token/tests/approve_checked.rs | 16 ++-- p-token/tests/batch.rs | 22 ++--- p-token/tests/burn.rs | 16 ++-- p-token/tests/burn_checked.rs | 16 ++-- p-token/tests/close_account.rs | 14 ++-- p-token/tests/freeze_account.rs | 18 ++-- p-token/tests/initialize_account.rs | 18 ++-- p-token/tests/initialize_account2.rs | 18 ++-- p-token/tests/initialize_account3.rs | 18 ++-- p-token/tests/initialize_mint.rs | 25 +++--- p-token/tests/initialize_mint2.rs | 25 +++--- p-token/tests/initialize_multisig.rs | 20 +++-- p-token/tests/initialize_multisig2.rs | 20 +++-- p-token/tests/mint_to.rs | 16 ++-- p-token/tests/mint_to_checked.rs | 16 ++-- p-token/tests/revoke.rs | 16 ++-- p-token/tests/set_authority.rs | 20 +++-- p-token/tests/setup/account.rs | 10 ++- p-token/tests/setup/mint.rs | 15 ++-- p-token/tests/thaw_account.rs | 18 ++-- p-token/tests/transfer.rs | 16 ++-- p-token/tests/transfer_checked.rs | 16 ++-- p-token/tests/ui_amount_to_amount.rs | 8 +- p-token/tests/withdraw_excess_lamports.rs | 26 +++--- package.json | 7 +- 72 files changed, 687 insertions(+), 521 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9b3c962..b311dc5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -61,6 +61,44 @@ jobs: - name: Lint run: pnpm programs:lint + format_and_lint_interface: + name: Format & Lint Interface + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + clippy: true + rustfmt: true + + - name: Format + run: pnpm interface:format + + - name: Lint + run: pnpm interface:lint + + format_and_lint_ptoken: + name: Format & Lint p-token + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + clippy: true + rustfmt: true + + - name: Format + run: pnpm p-token:format + + - name: Lint + run: pnpm p-token:lint + audit_rust: name: Audit Rust runs-on: ubuntu-latest @@ -154,6 +192,7 @@ jobs: build_ptoken: name: Build p-token runs-on: ubuntu-latest + needs: [format_and_lint_interface, format_and_lint_ptoken] steps: - name: Git Checkout uses: actions/checkout@v4 diff --git a/Cargo.toml b/Cargo.toml index 940ada8..95443b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" level = "warn" check-cfg = [ 'cfg(target_os, values("solana"))', - 'cfg(feature, values("frozen-abi", "no-entrypoint"))', + 'cfg(feature, values("custom-alloc", "custom-panic", "frozen-abi", "no-entrypoint"))', ] [workspace.metadata.cli] diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index 5b7b0ea..9b1e36c 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -65,11 +65,13 @@ pub enum TokenInstruction { /// /// 0. `[writable]` The multisignature account to initialize. /// 1. `[]` Rent sysvar. - /// 2. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <= 11`. + /// 2. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= + /// N <= 11`. /// /// Data expected by this instruction: /// - /// - `u8` The number of signers (M) required to validate this multisignature account. + /// - `u8` The number of signers (M) required to validate this + /// multisignature account. InitializeMultisig, /// Transfers tokens from one account to another either directly or via a @@ -268,7 +270,8 @@ pub enum TokenInstruction { /// Data expected by this instruction: /// /// - `u64` The amount of tokens to transfer. - /// - `u8` Expected number of base 10 digits to the right of the decimal place. + /// - `u8` Expected number of base 10 digits to the right of the decimal + /// place. TransferChecked, /// Approves a delegate. A delegate is given the authority over tokens on @@ -296,7 +299,8 @@ pub enum TokenInstruction { /// Data expected by this instruction: /// /// - `u64` The amount of tokens the delegate is approved for. - /// - `u8` Expected number of base 10 digits to the right of the decimal place. + /// - `u8` Expected number of base 10 digits to the right of the decimal + /// place. ApproveChecked, /// Mints new tokens to an account. The native mint does not support @@ -322,7 +326,8 @@ pub enum TokenInstruction { /// Data expected by this instruction: /// /// - `u64` The amount of new tokens to mint. - /// - `u8` Expected number of base 10 digits to the right of the decimal place. + /// - `u8` Expected number of base 10 digits to the right of the decimal + /// place. MintToChecked, /// Burns tokens by removing them from an account. [`BurnChecked`] does not @@ -349,13 +354,14 @@ pub enum TokenInstruction { /// Data expected by this instruction: /// /// - `u64` The amount of tokens to burn. - /// - `u8` Expected number of base 10 digits to the right of the decimal place. + /// - `u8` Expected number of base 10 digits to the right of the decimal + /// place. BurnChecked, - /// Like [`InitializeAccount`], but the owner pubkey is passed via instruction - /// data rather than the accounts list. This variant may be preferable - /// when using Cross Program Invocation from an instruction that does - /// not need the owner's `AccountInfo` otherwise. + /// Like [`InitializeAccount`], but the owner pubkey is passed via + /// instruction data rather than the accounts list. This variant may be + /// preferable when using Cross Program Invocation from an instruction + /// that does not need the owner's `AccountInfo` otherwise. /// /// Accounts expected by this instruction: /// @@ -399,11 +405,13 @@ pub enum TokenInstruction { /// Accounts expected by this instruction: /// /// 0. `[writable]` The multisignature account to initialize. - /// 1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= N <= 11`. + /// 1. `..+N` `[signer]` The signer accounts, must equal to N where `1 <= + /// N <= 11`. /// /// Data expected by this instruction: /// - /// - `u8` The number of signers (M) required to validate this multisignature account. + /// - `u8` The number of signers (M) required to validate this + /// multisignature account. InitializeMultisig2, /// Like [`InitializeMint`], but does not require the Rent sysvar to be @@ -462,9 +470,9 @@ pub enum TokenInstruction { /// - `u64` The amount of tokens to reformat. AmountToUiAmount, - /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount, using - /// the given mint. In this version of the program, the mint can only - /// specify the number of decimals. + /// Convert a `UiAmount` of tokens to a little-endian `u64` raw Amount, + /// using the given mint. In this version of the program, the mint can + /// only specify the number of decimals. /// /// Return data can be fetched using `sol_get_return_data` and deserializing /// the return data as a little-endian `u64`. @@ -490,22 +498,26 @@ pub enum TokenInstruction { /// 3. `..+M` `[signer]` M signer accounts. WithdrawExcessLamports = 38, - /// Executes a batch of instructions. The instructions to be executed are specified - /// in sequence on the instruction data. Each instruction provides: + /// Executes a batch of instructions. The instructions to be executed are + /// specified in sequence on the instruction data. Each instruction + /// provides: /// - `u8`: number of accounts /// - `u8`: instruction data length (includes the discriminator) /// - `u8`: instruction discriminator /// - `[u8]`: instruction data /// - /// Accounts follow a similar pattern, where accounts for each instruction are - /// specified in sequence. Therefore, the number of accounts expected by this - /// instruction is variable, i.e., it depends on the instructions provided. + /// Accounts follow a similar pattern, where accounts for each instruction + /// are specified in sequence. Therefore, the number of accounts + /// expected by this instruction is variable, i.e., it depends on the + /// instructions provided. /// - /// Both the number of accounts and instruction data length are used to identify - /// the slice of accounts and instruction data for each instruction. + /// Both the number of accounts and instruction data length are used to + /// identify the slice of accounts and instruction data for each + /// instruction. /// - /// Note that it is not sound to have a `batch` instruction that contains other - /// `batch` instruction; an error will be raised when this is detected. + /// Note that it is not sound to have a `batch` instruction that contains + /// other `batch` instruction; an error will be raised when this is + /// detected. Batch = 255, // Any new variants also need to be added to program-2022 `TokenInstruction`, so that the // latter remains a superset of this instruction set. New variants also need to be added to @@ -554,8 +566,10 @@ impl TryFrom for AuthorityType { #[cfg(test)] mod tests { - use super::{AuthorityType, TokenInstruction}; - use strum::IntoEnumIterator; + use { + super::{AuthorityType, TokenInstruction}, + strum::IntoEnumIterator, + }; #[test] fn test_token_instruction_from_u8_exhaustive() { diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index 9e5e2c0..ba8b145 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -1,6 +1,7 @@ -use pinocchio::pubkey::Pubkey; - -use super::{account_state::AccountState, COption, Initializable, Transmutable}; +use { + super::{account_state::AccountState, COption, Initializable, Transmutable}, + pinocchio::pubkey::Pubkey, +}; /// Incinerator address. pub const INCINERATOR_ID: Pubkey = diff --git a/interface/src/state/mint.rs b/interface/src/state/mint.rs index 46d6168..18c7bc5 100644 --- a/interface/src/state/mint.rs +++ b/interface/src/state/mint.rs @@ -1,6 +1,7 @@ -use pinocchio::pubkey::Pubkey; - -use super::{COption, Initializable, Transmutable}; +use { + super::{COption, Initializable, Transmutable}, + pinocchio::pubkey::Pubkey, +}; /// Internal representation of a mint data. #[repr(C)] diff --git a/interface/src/state/mod.rs b/interface/src/state/mod.rs index 28ba9f7..61128ff 100644 --- a/interface/src/state/mod.rs +++ b/interface/src/state/mod.rs @@ -10,8 +10,9 @@ pub type COption = ([u8; 4], T); /// Marker trait for types that can be cast from a raw pointer. /// -/// It is up to the type implementing this trait to guarantee that the cast is safe, -/// i.e., the fields of the type are well aligned and there are no padding bytes. +/// It is up to the type implementing this trait to guarantee that the cast is +/// safe, i.e., the fields of the type are well aligned and there are no padding +/// bytes. pub trait Transmutable { /// The length of the type. /// diff --git a/interface/src/state/multisig.rs b/interface/src/state/multisig.rs index d0ad7a3..caa08fb 100644 --- a/interface/src/state/multisig.rs +++ b/interface/src/state/multisig.rs @@ -1,6 +1,7 @@ -use pinocchio::pubkey::Pubkey; - -use super::{Initializable, Transmutable}; +use { + super::{Initializable, Transmutable}, + pinocchio::pubkey::Pubkey, +}; /// Minimum number of multisignature signers (min N) pub const MIN_SIGNERS: u8 = 1; @@ -25,7 +26,8 @@ pub struct Multisig { } impl Multisig { - /// Utility function that checks index is between [`MIN_SIGNERS`] and [`MAX_SIGNERS`]. + /// Utility function that checks index is between [`MIN_SIGNERS`] and + /// [`MAX_SIGNERS`]. pub fn is_valid_signer_index(index: u8) -> bool { (MIN_SIGNERS..=MAX_SIGNERS).contains(&index) } diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 03d6189..bfb6a41 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -27,3 +27,6 @@ solana-sdk = "2.1" spl-token = { version="^4", features=["no-entrypoint"] } spl-token-2022 = { version="^7", features=["no-entrypoint"] } test-case = "3.3.1" + +[lints] +workspace = true diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 0296dd9..1422c67 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -1,10 +1,11 @@ -use pinocchio::{ - account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint, - program_error::ProgramError, pubkey::Pubkey, ProgramResult, +use { + crate::processor::*, + pinocchio::{ + account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint, + program_error::ProgramError, pubkey::Pubkey, ProgramResult, + }, }; -use crate::processor::*; - program_entrypoint!(process_instruction); // Do not allocate memory. no_allocator!(); @@ -13,10 +14,11 @@ default_panic_handler!(); /// Process an instruction. /// -/// In the first stage, the entrypoint checks the discriminator of the instruction data -/// to determine whether the instruction is a "batch" instruction or a "regular" instruction. -/// This avoids nesting of "batch" instructions, since it is not sound to have a "batch" -/// instruction inside another "batch" instruction. +/// In the first stage, the entrypoint checks the discriminator of the +/// instruction data to determine whether the instruction is a "batch" +/// instruction or a "regular" instruction. This avoids nesting of "batch" +/// instructions, since it is not sound to have a "batch" instruction inside +/// another "batch" instruction. #[inline(always)] pub fn process_instruction( _program_id: &Pubkey, @@ -40,20 +42,21 @@ pub fn process_instruction( /// Process a "regular" instruction. /// -/// The processor of the token program is divided into two parts to reduce the overhead -/// of having a large `match` statement. The first part of the processor handles the -/// most common instructions, while the second part handles the remaining instructions. +/// The processor of the token program is divided into two parts to reduce the +/// overhead of having a large `match` statement. The first part of the +/// processor handles the most common instructions, while the second part +/// handles the remaining instructions. /// -/// The rationale is to reduce the overhead of making multiple comparisons for popular -/// instructions. +/// The rationale is to reduce the overhead of making multiple comparisons for +/// popular instructions. /// /// Instructions on the first part of the inner processor: /// -/// - `0`: `InitializeMint` -/// - `1`: `InitializeAccount` -/// - `3`: `Transfer` -/// - `7`: `MintTo` -/// - `9`: `CloseAccount` +/// - `0`: `InitializeMint` +/// - `1`: `InitializeAccount` +/// - `3`: `Transfer` +/// - `7`: `MintTo` +/// - `9`: `CloseAccount` /// - `16`: `InitializeAccount2` /// - `18`: `InitializeAccount3` /// - `20`: `InitializeMint2` @@ -129,9 +132,10 @@ pub(crate) fn inner_process_instruction( /// Process a remaining "regular" instruction. /// -/// This function is called by the [`inner_process_instruction`] function if the discriminator -/// does not match any of the common instructions. This function is used to reduce the -/// overhead of having a large `match` statement in the [`inner_process_instruction`] function. +/// This function is called by the [`inner_process_instruction`] function if the +/// discriminator does not match any of the common instructions. This function +/// is used to reduce the overhead of having a large `match` statement in the +/// [`inner_process_instruction`] function. fn inner_process_remaining_instruction( accounts: &[AccountInfo], instruction_data: &[u8], diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index b90fcf8..5f58bda 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -1,14 +1,16 @@ -use core::str::from_utf8_unchecked; -use pinocchio::{ - account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, +use { + super::{check_account_owner, MAX_FORMATTED_DIGITS}, + core::str::from_utf8_unchecked, + pinocchio::{ + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, + ProgramResult, + }, + pinocchio_log::logger::{Argument, Logger}, + spl_token_interface::{ + error::TokenError, + state::{load, mint::Mint}, + }, }; -use pinocchio_log::logger::{Argument, Logger}; -use spl_token_interface::{ - error::TokenError, - state::{load, mint::Mint}, -}; - -use super::{check_account_owner, MAX_FORMATTED_DIGITS}; #[inline(always)] pub fn process_amount_to_ui_amount( diff --git a/p-token/src/processor/approve.rs b/p-token/src/processor/approve.rs index 10c61ed..a24846f 100644 --- a/p-token/src/processor/approve.rs +++ b/p-token/src/processor/approve.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_approve(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/approve_checked.rs b/p-token/src/processor/approve_checked.rs index f9a8230..c2a2185 100644 --- a/p-token/src/processor/approve_checked.rs +++ b/p-token/src/processor/approve_checked.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_approve_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/batch.rs b/p-token/src/processor/batch.rs index 6c94208..501f08b 100644 --- a/p-token/src/processor/batch.rs +++ b/p-token/src/processor/batch.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use crate::entrypoint::inner_process_instruction; +use { + crate::entrypoint::inner_process_instruction, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; /// The size of the batch instruction header. /// @@ -9,6 +10,7 @@ use crate::entrypoint::inner_process_instruction; /// * length of the instruction data const IX_HEADER_SIZE: usize = 2; +#[allow(clippy::arithmetic_side_effects)] pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8]) -> ProgramResult { loop { // Validates the instruction data and accounts offset. @@ -18,8 +20,9 @@ pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8]) return Err(ProgramError::InvalidInstructionData); } - // SAFETY: The instruction data is guaranteed to have at least two bytes (header) - // + one byte (discriminator). + // SAFETY: The instruction data is guaranteed to have at least two bytes + // (header) + one byte (discriminator) and the values are within the bounds + // of an `usize`. let expected_accounts = unsafe { *instruction_data.get_unchecked(0) as usize }; let data_offset = IX_HEADER_SIZE + unsafe { *instruction_data.get_unchecked(1) as usize }; @@ -33,8 +36,8 @@ pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8]) // Process the instruction. - // SAFETY: The instruction data and accounts lengths are already validated so all - // slices are guaranteed to be valid. + // SAFETY: The instruction data and accounts lengths are already validated so + // all slices are guaranteed to be valid. let (ix_accounts, ix_data) = unsafe { ( accounts.get_unchecked(..expected_accounts), diff --git a/p-token/src/processor/burn.rs b/p-token/src/processor/burn.rs index 6ceed84..e964696 100644 --- a/p-token/src/processor/burn.rs +++ b/p-token/src/processor/burn.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_burn(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/burn_checked.rs b/p-token/src/processor/burn_checked.rs index 2c8a134..5501c0f 100644 --- a/p-token/src/processor/burn_checked.rs +++ b/p-token/src/processor/burn_checked.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_burn_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/close_account.rs b/p-token/src/processor/close_account.rs index 21cfc4d..0fa979b 100644 --- a/p-token/src/processor/close_account.rs +++ b/p-token/src/processor/close_account.rs @@ -1,14 +1,15 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{ - account::{Account, INCINERATOR_ID}, - load, +use { + super::validate_owner, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{ + account::{Account, INCINERATOR_ID}, + load, + }, }, }; -use super::validate_owner; - #[inline(always)] pub fn process_close_account(accounts: &[AccountInfo]) -> ProgramResult { let [source_account_info, destination_account_info, authority_info, remaining @ ..] = accounts diff --git a/p-token/src/processor/freeze_account.rs b/p-token/src/processor/freeze_account.rs index 5637611..568d7a2 100644 --- a/p-token/src/processor/freeze_account.rs +++ b/p-token/src/processor/freeze_account.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, ProgramResult}; - -use super::shared::toggle_account_state::process_toggle_account_state; +use { + super::shared::toggle_account_state::process_toggle_account_state, + pinocchio::{account_info::AccountInfo, ProgramResult}, +}; #[inline(always)] pub fn process_freeze_account(accounts: &[AccountInfo]) -> ProgramResult { diff --git a/p-token/src/processor/get_account_data_size.rs b/p-token/src/processor/get_account_data_size.rs index 690abf1..08502a1 100644 --- a/p-token/src/processor/get_account_data_size.rs +++ b/p-token/src/processor/get_account_data_size.rs @@ -1,12 +1,14 @@ -use pinocchio::{ - account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, +use { + super::check_account_owner, + pinocchio::{ + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, + ProgramResult, + }, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load, mint::Mint, Transmutable}, + }, }; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load, mint::Mint, Transmutable}, -}; - -use super::check_account_owner; #[inline(always)] pub fn process_get_account_data_size(accounts: &[AccountInfo]) -> ProgramResult { diff --git a/p-token/src/processor/initialize_account.rs b/p-token/src/processor/initialize_account.rs index 2c12509..4ad3f2c 100644 --- a/p-token/src/processor/initialize_account.rs +++ b/p-token/src/processor/initialize_account.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, ProgramResult}, +}; #[inline(always)] pub fn process_initialize_account(accounts: &[AccountInfo]) -> ProgramResult { diff --git a/p-token/src/processor/initialize_account2.rs b/p-token/src/processor/initialize_account2.rs index f28ec3c..04a1bf8 100644 --- a/p-token/src/processor/initialize_account2.rs +++ b/p-token/src/processor/initialize_account2.rs @@ -1,9 +1,10 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +use { + super::shared, + pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, + }, }; -use super::shared; - #[inline(always)] pub fn process_initialize_account2( accounts: &[AccountInfo], diff --git a/p-token/src/processor/initialize_account3.rs b/p-token/src/processor/initialize_account3.rs index 8aca410..0863681 100644 --- a/p-token/src/processor/initialize_account3.rs +++ b/p-token/src/processor/initialize_account3.rs @@ -1,9 +1,10 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +use { + super::shared, + pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, + }, }; -use super::shared; - #[inline(always)] pub fn process_initialize_account3( accounts: &[AccountInfo], diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs index db39cbd..60bd26a 100644 --- a/p-token/src/processor/initialize_immutable_owner.rs +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -1,7 +1,9 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load_unchecked, Initializable}, +use { + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load_unchecked, Initializable}, + }, }; #[inline(always)] diff --git a/p-token/src/processor/initialize_mint.rs b/p-token/src/processor/initialize_mint.rs index 3d5b5f5..c692ca7 100644 --- a/p-token/src/processor/initialize_mint.rs +++ b/p-token/src/processor/initialize_mint.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, ProgramResult}, +}; #[inline(always)] pub fn process_initialize_mint(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/initialize_mint2.rs b/p-token/src/processor/initialize_mint2.rs index 41b2c0b..fda4e54 100644 --- a/p-token/src/processor/initialize_mint2.rs +++ b/p-token/src/processor/initialize_mint2.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, ProgramResult}; - -use super::shared::initialize_mint::process_initialize_mint; +use { + super::shared::initialize_mint::process_initialize_mint, + pinocchio::{account_info::AccountInfo, ProgramResult}, +}; #[inline(always)] pub fn process_initialize_mint2( diff --git a/p-token/src/processor/initialize_multisig.rs b/p-token/src/processor/initialize_multisig.rs index a5f888b..b175a3b 100644 --- a/p-token/src/processor/initialize_multisig.rs +++ b/p-token/src/processor/initialize_multisig.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_initialize_multisig( diff --git a/p-token/src/processor/initialize_multisig2.rs b/p-token/src/processor/initialize_multisig2.rs index 138a91b..884decc 100644 --- a/p-token/src/processor/initialize_multisig2.rs +++ b/p-token/src/processor/initialize_multisig2.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_initialize_multisig2( diff --git a/p-token/src/processor/mint_to.rs b/p-token/src/processor/mint_to.rs index 59db533..ca22c60 100644 --- a/p-token/src/processor/mint_to.rs +++ b/p-token/src/processor/mint_to.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_mint_to(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/mint_to_checked.rs b/p-token/src/processor/mint_to_checked.rs index 2386bf5..b7703bd 100644 --- a/p-token/src/processor/mint_to_checked.rs +++ b/p-token/src/processor/mint_to_checked.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_mint_to_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 5182e83..a2ba93a 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -1,15 +1,17 @@ -use core::{slice::from_raw_parts, str::from_utf8_unchecked}; -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, syscalls::sol_memcpy_, - ProgramResult, -}; -use spl_token_interface::{ - error::TokenError, - program::ID as TOKEN_PROGRAM_ID, - state::{ - load, - multisig::{Multisig, MAX_SIGNERS}, - Transmutable, +use { + core::{slice::from_raw_parts, str::from_utf8_unchecked}, + pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, + syscalls::sol_memcpy_, ProgramResult, + }, + spl_token_interface::{ + error::TokenError, + program::ID as TOKEN_PROGRAM_ID, + state::{ + load, + multisig::{Multisig, MAX_SIGNERS}, + Transmutable, + }, }, }; @@ -43,33 +45,24 @@ pub mod withdraw_excess_lamports; // Shared processors. pub mod shared; -pub use amount_to_ui_amount::process_amount_to_ui_amount; -pub use approve::process_approve; -pub use approve_checked::process_approve_checked; -pub use batch::process_batch; -pub use burn::process_burn; -pub use burn_checked::process_burn_checked; -pub use close_account::process_close_account; -pub use freeze_account::process_freeze_account; -pub use get_account_data_size::process_get_account_data_size; -pub use initialize_account::process_initialize_account; -pub use initialize_account2::process_initialize_account2; -pub use initialize_account3::process_initialize_account3; -pub use initialize_immutable_owner::process_initialize_immutable_owner; -pub use initialize_mint::process_initialize_mint; -pub use initialize_mint2::process_initialize_mint2; -pub use initialize_multisig::process_initialize_multisig; -pub use initialize_multisig2::process_initialize_multisig2; -pub use mint_to::process_mint_to; -pub use mint_to_checked::process_mint_to_checked; -pub use revoke::process_revoke; -pub use set_authority::process_set_authority; -pub use sync_native::process_sync_native; -pub use thaw_account::process_thaw_account; -pub use transfer::process_transfer; -pub use transfer_checked::process_transfer_checked; -pub use ui_amount_to_amount::process_ui_amount_to_amount; -pub use withdraw_excess_lamports::process_withdraw_excess_lamports; +pub use { + amount_to_ui_amount::process_amount_to_ui_amount, approve::process_approve, + approve_checked::process_approve_checked, batch::process_batch, burn::process_burn, + burn_checked::process_burn_checked, close_account::process_close_account, + freeze_account::process_freeze_account, get_account_data_size::process_get_account_data_size, + initialize_account::process_initialize_account, + initialize_account2::process_initialize_account2, + initialize_account3::process_initialize_account3, + initialize_immutable_owner::process_initialize_immutable_owner, + initialize_mint::process_initialize_mint, initialize_mint2::process_initialize_mint2, + initialize_multisig::process_initialize_multisig, + initialize_multisig2::process_initialize_multisig2, mint_to::process_mint_to, + mint_to_checked::process_mint_to_checked, revoke::process_revoke, + set_authority::process_set_authority, sync_native::process_sync_native, + thaw_account::process_thaw_account, transfer::process_transfer, + transfer_checked::process_transfer_checked, ui_amount_to_amount::process_ui_amount_to_amount, + withdraw_excess_lamports::process_withdraw_excess_lamports, +}; /// Maximum number of digits in a formatted `u64`. /// @@ -94,6 +87,7 @@ fn check_account_owner(account_info: &AccountInfo) -> ProgramResult { /// a multisig account, therefore it should not have any mutable borrows when /// calling this function. #[inline(always)] +#[allow(clippy::arithmetic_side_effects)] fn validate_owner( expected_owner: &Pubkey, owner_account_info: &AccountInfo, @@ -106,10 +100,11 @@ fn validate_owner( if owner_account_info.data_len() == Multisig::LEN && owner_account_info.owner() == &TOKEN_PROGRAM_ID { - // SAFETY: the caller guarantees that there are no mutable borrows of `owner_account_info` - // account data and the `load` validates that the account is initialized; additionally, - // `Multisig` accounts are only ever loaded in this function, which means that previous - // loads will have already failed by the time we get here. + // SAFETY: the caller guarantees that there are no mutable borrows of + // `owner_account_info` account data and the `load` validates that the + // account is initialized; additionally, `Multisig` accounts are only + // ever loaded in this function, which means that previous loads will + // have already failed by the time we get here. let multisig = unsafe { load::(owner_account_info.borrow_data_unchecked())? }; let mut num_signers = 0; @@ -138,6 +133,7 @@ fn validate_owner( /// Try to convert a UI representation of a token amount to its raw amount using /// the given decimals field +#[allow(clippy::arithmetic_side_effects)] fn try_ui_amount_into_amount(ui_amount: &str, decimals: u8) -> Result { let decimals = decimals as usize; let mut parts = ui_amount.split('.'); diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs index 936b73a..56ceba1 100644 --- a/p-token/src/processor/revoke.rs +++ b/p-token/src/processor/revoke.rs @@ -1,11 +1,12 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load_mut}, +use { + super::validate_owner, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load_mut}, + }, }; -use super::validate_owner; - #[inline(always)] pub fn process_revoke(accounts: &[AccountInfo], _instruction_data: &[u8]) -> ProgramResult { let [source_account_info, owner_info, remaining @ ..] = accounts else { diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index b621eeb..81a8ce3 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -1,13 +1,14 @@ -use pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, +use { + super::validate_owner, + pinocchio::{ + account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, + }, + spl_token_interface::{ + error::TokenError, + instruction::AuthorityType, + state::{account::Account, load_mut, mint::Mint, Transmutable}, + }, }; -use spl_token_interface::{ - error::TokenError, - instruction::AuthorityType, - state::{account::Account, load_mut, mint::Mint, Transmutable}, -}; - -use super::validate_owner; #[inline(always)] pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/shared/approve.rs b/p-token/src/processor/shared/approve.rs index 22bae66..520ccb8 100644 --- a/p-token/src/processor/shared/approve.rs +++ b/p-token/src/processor/shared/approve.rs @@ -1,19 +1,20 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load, load_mut, mint::Mint}, +use { + crate::processor::validate_owner, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load, load_mut, mint::Mint}, + }, }; -use crate::processor::validate_owner; - #[inline(always)] pub fn process_approve( accounts: &[AccountInfo], amount: u64, expected_decimals: Option, ) -> ProgramResult { - // Accounts expected depend on whether we have the mint `decimals` or not; when we have the - // mint `decimals`, we expect the mint account to be present. + // Accounts expected depend on whether we have the mint `decimals` or not; when + // we have the mint `decimals`, we expect the mint account to be present. let (source_account_info, expected_mint_info, delegate_info, owner_info, remaining) = if let Some(expected_decimals) = expected_decimals { diff --git a/p-token/src/processor/shared/burn.rs b/p-token/src/processor/shared/burn.rs index abb250a..6a3511e 100644 --- a/p-token/src/processor/shared/burn.rs +++ b/p-token/src/processor/shared/burn.rs @@ -1,11 +1,12 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load_mut, mint::Mint}, +use { + crate::processor::{check_account_owner, validate_owner}, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load_mut, mint::Mint}, + }, }; -use crate::processor::{check_account_owner, validate_owner}; - #[inline(always)] pub fn process_burn( accounts: &[AccountInfo], diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index b87d034..897318d 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -1,22 +1,24 @@ -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::Pubkey, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, -}; -use spl_token_interface::{ - error::TokenError, - native_mint::is_native_mint, - state::{ - account::Account, account_state::AccountState, load, load_mut_unchecked, mint::Mint, - Initializable, +use { + crate::processor::check_account_owner, + pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::Pubkey, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, + }, + spl_token_interface::{ + error::TokenError, + native_mint::is_native_mint, + state::{ + account::Account, account_state::AccountState, load, load_mut_unchecked, mint::Mint, + Initializable, + }, }, }; -use crate::processor::check_account_owner; - #[inline(always)] +#[allow(clippy::arithmetic_side_effects)] pub fn process_initialize_account( accounts: &[AccountInfo], owner: Option<&Pubkey>, @@ -44,8 +46,8 @@ pub fn process_initialize_account( let rent_sysvar_info = remaining .first() .ok_or(ProgramError::NotEnoughAccountKeys)?; - // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are - // checked by `from_account_info_unchecked`. + // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length + // are checked by `from_account_info_unchecked`. let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; rent.minimum_balance(new_account_info_data_len) } else { diff --git a/p-token/src/processor/shared/initialize_mint.rs b/p-token/src/processor/shared/initialize_mint.rs index 657f575..d53f668 100644 --- a/p-token/src/processor/shared/initialize_mint.rs +++ b/p-token/src/processor/shared/initialize_mint.rs @@ -1,14 +1,16 @@ -use core::mem::size_of; -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - pubkey::Pubkey, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, -}; -use spl_token_interface::{ - error::TokenError, - state::{load_mut_unchecked, mint::Mint, Initializable}, +use { + core::mem::size_of, + pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + pubkey::Pubkey, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, + }, + spl_token_interface::{ + error::TokenError, + state::{load_mut_unchecked, mint::Mint, Initializable}, + }, }; #[inline(always)] @@ -63,8 +65,8 @@ pub fn process_initialize_mint( // Check rent-exempt status of the mint account. let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { - // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are - // checked by `from_account_info_unchecked`. + // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length + // are checked by `from_account_info_unchecked`. let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; rent.is_exempt(mint_info.lamports(), size_of::()) } else { diff --git a/p-token/src/processor/shared/initialize_multisig.rs b/p-token/src/processor/shared/initialize_multisig.rs index 00480ff..8335f04 100644 --- a/p-token/src/processor/shared/initialize_multisig.rs +++ b/p-token/src/processor/shared/initialize_multisig.rs @@ -1,12 +1,14 @@ -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, -}; -use spl_token_interface::{ - error::TokenError, - state::{load_mut_unchecked, multisig::Multisig, Initializable}, +use { + pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, + }, + spl_token_interface::{ + error::TokenError, + state::{load_mut_unchecked, multisig::Multisig, Initializable}, + }, }; #[inline(always)] @@ -32,8 +34,8 @@ pub fn process_initialize_multisig( let multisig_info_data_len = multisig_info.data_len(); let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { - // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length are - // checked by `from_account_info_unchecked`. + // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length + // are checked by `from_account_info_unchecked`. let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) } else { diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs index 14aabba..643da08 100644 --- a/p-token/src/processor/shared/mint_to.rs +++ b/p-token/src/processor/shared/mint_to.rs @@ -1,12 +1,14 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load_mut, mint::Mint}, +use { + crate::processor::{check_account_owner, validate_owner}, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load_mut, mint::Mint}, + }, }; -use crate::processor::{check_account_owner, validate_owner}; - #[inline(always)] +#[allow(clippy::arithmetic_side_effects)] pub fn process_mint_to( accounts: &[AccountInfo], amount: u64, diff --git a/p-token/src/processor/shared/toggle_account_state.rs b/p-token/src/processor/shared/toggle_account_state.rs index 6683819..cad0669 100644 --- a/p-token/src/processor/shared/toggle_account_state.rs +++ b/p-token/src/processor/shared/toggle_account_state.rs @@ -1,11 +1,12 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, account_state::AccountState, load, load_mut, mint::Mint}, +use { + crate::processor::validate_owner, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{account::Account, account_state::AccountState, load, load_mut, mint::Mint}, + }, }; -use crate::processor::validate_owner; - #[inline(always)] pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> ProgramResult { let [source_account_info, mint_info, authority_info, remaining @ ..] = accounts else { diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index 2868678..80aaac5 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -1,19 +1,21 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load, load_mut, load_mut_unchecked, mint::Mint}, +use { + crate::processor::{check_account_owner, validate_owner}, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load, load_mut, load_mut_unchecked, mint::Mint}, + }, }; -use crate::processor::{check_account_owner, validate_owner}; - #[inline(always)] +#[allow(clippy::arithmetic_side_effects)] pub fn process_transfer( accounts: &[AccountInfo], amount: u64, expected_decimals: Option, ) -> ProgramResult { - // Accounts expected depend on whether we have the mint `decimals` or not; when we have the - // mint `decimals`, we expect the mint account to be present. + // Accounts expected depend on whether we have the mint `decimals` or not; when + // we have the mint `decimals`, we expect the mint account to be present. let ( source_account_info, @@ -68,8 +70,8 @@ pub fn process_transfer( // Note: the logic is partially duplicated for self transfers and transfers // to different accounts to improve CU consumption: // - // - self-transfer: we only need to check that the source account is not frozen - // and has enough tokens. + // - self-transfer: we only need to check that the source account is not + // frozen and has enough tokens. // // - transfers to different accounts: we need to check that the source and // destination accounts are not frozen, have the same mint, and the source @@ -84,9 +86,9 @@ pub fn process_transfer( .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)? } else { - // SAFETY: scoped immutable borrow to `destination_account_info` account data and - // `load` validates that the account is initialized; additionally, the account - // is guaranteed to be different than `source_account_info`. + // SAFETY: scoped immutable borrow to `destination_account_info` account data + // and `load` validates that the account is initialized; additionally, + // the account is guaranteed to be different than `source_account_info`. let destination_account = unsafe { load::(destination_account_info.borrow_data_unchecked())? }; @@ -153,9 +155,10 @@ pub fn process_transfer( source_account.set_amount(remaining_amount); - // SAFETY: single mutable borrow to `destination_account_info` account data; the account - // is guaranteed to be initialized and different than `source_account_info`; it was - // also already validated to be a token account. + // SAFETY: single mutable borrow to `destination_account_info` account data; the + // account is guaranteed to be initialized and different than + // `source_account_info`; it was also already validated to be a token + // account. let destination_account = unsafe { load_mut_unchecked::(destination_account_info.borrow_mut_data_unchecked())? }; @@ -170,8 +173,9 @@ pub fn process_transfer( .checked_sub(amount) .ok_or(TokenError::Overflow)?; - // SAFETY: single mutable borrow to `destination_account_info` lamports; the account - // is already validated to be different from `source_account_info`. + // SAFETY: single mutable borrow to `destination_account_info` lamports; the + // account is already validated to be different from + // `source_account_info`. let destination_lamports = unsafe { destination_account_info.borrow_mut_lamports_unchecked() }; *destination_lamports = destination_lamports diff --git a/p-token/src/processor/sync_native.rs b/p-token/src/processor/sync_native.rs index 8507e59..4a9b7eb 100644 --- a/p-token/src/processor/sync_native.rs +++ b/p-token/src/processor/sync_native.rs @@ -1,11 +1,12 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load_mut}, +use { + super::check_account_owner, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load_mut}, + }, }; -use super::check_account_owner; - #[inline(always)] pub fn process_sync_native(accounts: &[AccountInfo]) -> ProgramResult { let native_account_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; diff --git a/p-token/src/processor/thaw_account.rs b/p-token/src/processor/thaw_account.rs index 924d3b6..464b1e8 100644 --- a/p-token/src/processor/thaw_account.rs +++ b/p-token/src/processor/thaw_account.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, ProgramResult}; - -use super::shared::toggle_account_state::process_toggle_account_state; +use { + super::shared::toggle_account_state::process_toggle_account_state, + pinocchio::{account_info::AccountInfo, ProgramResult}, +}; #[inline(always)] pub fn process_thaw_account(accounts: &[AccountInfo]) -> ProgramResult { diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs index 52af330..eadb03d 100644 --- a/p-token/src/processor/transfer.rs +++ b/p-token/src/processor/transfer.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_transfer(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { diff --git a/p-token/src/processor/transfer_checked.rs b/p-token/src/processor/transfer_checked.rs index b688cd4..16f742d 100644 --- a/p-token/src/processor/transfer_checked.rs +++ b/p-token/src/processor/transfer_checked.rs @@ -1,6 +1,7 @@ -use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}; - -use super::shared; +use { + super::shared, + pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, +}; #[inline(always)] pub fn process_transfer_checked( diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index b4c5b2e..879e5c0 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -1,13 +1,15 @@ -use core::str::from_utf8; -use pinocchio::{ - account_info::AccountInfo, program::set_return_data, program_error::ProgramError, ProgramResult, +use { + super::{check_account_owner, try_ui_amount_into_amount}, + core::str::from_utf8, + pinocchio::{ + account_info::AccountInfo, program::set_return_data, program_error::ProgramError, + ProgramResult, + }, + spl_token_interface::{ + error::TokenError, + state::{load, mint::Mint}, + }, }; -use spl_token_interface::{ - error::TokenError, - state::{load, mint::Mint}, -}; - -use super::{check_account_owner, try_ui_amount_into_amount}; #[inline(always)] pub fn process_ui_amount_to_amount( diff --git a/p-token/src/processor/withdraw_excess_lamports.rs b/p-token/src/processor/withdraw_excess_lamports.rs index 44e9015..cf5ca0e 100644 --- a/p-token/src/processor/withdraw_excess_lamports.rs +++ b/p-token/src/processor/withdraw_excess_lamports.rs @@ -1,17 +1,19 @@ -use pinocchio::{ - account_info::AccountInfo, - program_error::ProgramError, - sysvars::{rent::Rent, Sysvar}, - ProgramResult, +use { + super::validate_owner, + pinocchio::{ + account_info::AccountInfo, + program_error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + ProgramResult, + }, + spl_token_interface::{ + error::TokenError, + state::{account::Account, load, mint::Mint, multisig::Multisig, Transmutable}, + }, }; -use spl_token_interface::{ - error::TokenError, - state::{account::Account, load, mint::Mint, multisig::Multisig, Transmutable}, -}; - -use super::validate_owner; #[inline(always)] +#[allow(clippy::arithmetic_side_effects)] pub fn process_withdraw_excess_lamports(accounts: &[AccountInfo]) -> ProgramResult { let [source_account_info, destination_info, authority_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -61,8 +63,8 @@ pub fn process_withdraw_excess_lamports(accounts: &[AccountInfo]) -> ProgramResu unsafe { // Moves the lamports out of the source account. // - // Note: The `transfer_amount` is guaranteed to be less than the source account's - // lamports. + // Note: The `transfer_amount` is guaranteed to be less than the source + // account's lamports. *source_account_info.borrow_mut_lamports_unchecked() = source_starting_lamports - transfer_amount; } diff --git a/p-token/tests/amount_to_ui_amount.rs b/p-token/tests/amount_to_ui_amount.rs index a8de531..6504605 100644 --- a/p-token/tests/amount_to_ui_amount.rs +++ b/p-token/tests/amount_to_ui_amount.rs @@ -1,8 +1,10 @@ mod setup; -use setup::{mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; +use { + setup::{mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}, +}; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/approve.rs b/p-token/tests/approve.rs index dbc606a..b0ce007 100644 --- a/p-token/tests/approve.rs +++ b/p-token/tests/approve.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs index 3fb7c75..2080b15 100644 --- a/p-token/tests/approve_checked.rs +++ b/p-token/tests/approve_checked.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/batch.rs b/p-token/tests/batch.rs index f2cc481..4c837c4 100644 --- a/p-token/tests/batch.rs +++ b/p-token/tests/batch.rs @@ -1,15 +1,17 @@ mod setup; -use crate::setup::TOKEN_PROGRAM_ID; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - instruction::{AccountMeta, Instruction}, - program_error::ProgramError, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, +use { + crate::setup::TOKEN_PROGRAM_ID, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + instruction::{AccountMeta, Instruction}, + program_error::ProgramError, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, }; fn batch_instruction(instructions: Vec) -> Result { diff --git a/p-token/tests/burn.rs b/p-token/tests/burn.rs index 67ffb90..7fdaa46 100644 --- a/p-token/tests/burn.rs +++ b/p-token/tests/burn.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/burn_checked.rs b/p-token/tests/burn_checked.rs index a28a8b1..28c8e91 100644 --- a/p-token/tests/burn_checked.rs +++ b/p-token/tests/burn_checked.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/close_account.rs b/p-token/tests/close_account.rs index b9ca15a..9fb3e6f 100644 --- a/p-token/tests/close_account.rs +++ b/p-token/tests/close_account.rs @@ -1,11 +1,13 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/freeze_account.rs b/p-token/tests/freeze_account.rs index 0e8c498..219d0b4 100644 --- a/p-token/tests/freeze_account.rs +++ b/p-token/tests/freeze_account.rs @@ -1,14 +1,16 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token::state::AccountState, }; -use spl_token::state::AccountState; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/initialize_account.rs b/p-token/tests/initialize_account.rs index 0980b97..f55ba66 100644 --- a/p-token/tests/initialize_account.rs +++ b/p-token/tests/initialize_account.rs @@ -1,13 +1,15 @@ mod setup; -use setup::{mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, +use { + setup::{mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/initialize_account2.rs b/p-token/tests/initialize_account2.rs index 0e91266..2de157c 100644 --- a/p-token/tests/initialize_account2.rs +++ b/p-token/tests/initialize_account2.rs @@ -1,13 +1,15 @@ mod setup; -use setup::{mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, +use { + setup::{mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/initialize_account3.rs b/p-token/tests/initialize_account3.rs index a2349aa..fe470bf 100644 --- a/p-token/tests/initialize_account3.rs +++ b/p-token/tests/initialize_account3.rs @@ -1,13 +1,15 @@ mod setup; -use setup::{mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, +use { + setup::{mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/initialize_mint.rs b/p-token/tests/initialize_mint.rs index 4a761a2..2c68c14 100644 --- a/p-token/tests/initialize_mint.rs +++ b/p-token/tests/initialize_mint.rs @@ -1,18 +1,19 @@ mod setup; -use std::mem::size_of; - -use setup::TOKEN_PROGRAM_ID; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, +use { + setup::TOKEN_PROGRAM_ID, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_option::COption, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, + spl_token_interface::state::mint::Mint, + std::mem::size_of, }; -use spl_token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index 7cf32c5..819ba72 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -1,18 +1,19 @@ mod setup; -use std::mem::size_of; - -use setup::TOKEN_PROGRAM_ID; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, +use { + setup::TOKEN_PROGRAM_ID, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_option::COption, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, + spl_token_interface::state::mint::Mint, + std::mem::size_of, }; -use spl_token_interface::state::mint::Mint; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 9715545..14e126a 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -1,15 +1,17 @@ mod setup; -use setup::TOKEN_PROGRAM_ID; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, +use { + setup::TOKEN_PROGRAM_ID, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, + spl_token::state::Multisig, }; -use spl_token::state::Multisig; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index d380b3c..b8de8fe 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -1,15 +1,17 @@ mod setup; -use setup::TOKEN_PROGRAM_ID; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::Transaction, +use { + setup::TOKEN_PROGRAM_ID, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::Transaction, + }, + spl_token::state::Multisig, }; -use spl_token::state::Multisig; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index 96722ac..fdabcc8 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs index f80bd35..2a3b69c 100644 --- a/p-token/tests/mint_to_checked.rs +++ b/p-token/tests/mint_to_checked.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/revoke.rs b/p-token/tests/revoke.rs index 2be0ba2..43fd34c 100644 --- a/p-token/tests/revoke.rs +++ b/p-token/tests/revoke.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/set_authority.rs b/p-token/tests/set_authority.rs index 2b50005..c96ee2b 100644 --- a/p-token/tests/set_authority.rs +++ b/p-token/tests/set_authority.rs @@ -1,15 +1,17 @@ mod setup; -use setup::{mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_option::COption, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_option::COption, + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token::instruction::AuthorityType, }; -use spl_token::instruction::AuthorityType; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/setup/account.rs b/p-token/tests/setup/account.rs index cb2a097..f7734cf 100644 --- a/p-token/tests/setup/account.rs +++ b/p-token/tests/setup/account.rs @@ -1,7 +1,9 @@ -use solana_program_test::ProgramTestContext; -use solana_sdk::{ - pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, - transaction::Transaction, +use { + solana_program_test::ProgramTestContext, + solana_sdk::{ + pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, + transaction::Transaction, + }, }; pub async fn initialize( diff --git a/p-token/tests/setup/mint.rs b/p-token/tests/setup/mint.rs index dd8ceec..14b0735 100644 --- a/p-token/tests/setup/mint.rs +++ b/p-token/tests/setup/mint.rs @@ -1,11 +1,12 @@ -use std::mem::size_of; - -use solana_program_test::{BanksClientError, ProgramTestContext}; -use solana_sdk::{ - program_error::ProgramError, pubkey::Pubkey, signature::Keypair, signer::Signer, - system_instruction, transaction::Transaction, +use { + solana_program_test::{BanksClientError, ProgramTestContext}, + solana_sdk::{ + program_error::ProgramError, pubkey::Pubkey, signature::Keypair, signer::Signer, + system_instruction, transaction::Transaction, + }, + spl_token_interface::state::mint::Mint, + std::mem::size_of, }; -use spl_token_interface::state::mint::Mint; pub async fn initialize( context: &mut ProgramTestContext, diff --git a/p-token/tests/thaw_account.rs b/p-token/tests/thaw_account.rs index b00506a..be99451 100644 --- a/p-token/tests/thaw_account.rs +++ b/p-token/tests/thaw_account.rs @@ -1,14 +1,16 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, + spl_token::state::AccountState, }; -use spl_token::state::AccountState; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index e2bd377..de6bd5e 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs index b599946..9a5ca0c 100644 --- a/p-token/tests/transfer_checked.rs +++ b/p-token/tests/transfer_checked.rs @@ -1,12 +1,14 @@ mod setup; -use setup::{account, mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{ - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - transaction::Transaction, +use { + setup::{account, mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{ + program_pack::Pack, + pubkey::Pubkey, + signature::{Keypair, Signer}, + transaction::Transaction, + }, }; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] diff --git a/p-token/tests/ui_amount_to_amount.rs b/p-token/tests/ui_amount_to_amount.rs index 3e4754c..2fc9a9d 100644 --- a/p-token/tests/ui_amount_to_amount.rs +++ b/p-token/tests/ui_amount_to_amount.rs @@ -1,8 +1,10 @@ mod setup; -use setup::{mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, ProgramTest}; -use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}; +use { + setup::{mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, ProgramTest}, + solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}, +}; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/p-token/tests/withdraw_excess_lamports.rs b/p-token/tests/withdraw_excess_lamports.rs index 6e56c0c..3d41e2a 100644 --- a/p-token/tests/withdraw_excess_lamports.rs +++ b/p-token/tests/withdraw_excess_lamports.rs @@ -1,17 +1,21 @@ +#![allow(clippy::arithmetic_side_effects)] + mod setup; -use assert_matches::assert_matches; -use setup::{mint, TOKEN_PROGRAM_ID}; -use solana_program_test::{tokio, BanksClientError, ProgramTest}; -use solana_sdk::{ - instruction::InstructionError, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, - transaction::{Transaction, TransactionError}, +use { + assert_matches::assert_matches, + setup::{mint, TOKEN_PROGRAM_ID}, + solana_program_test::{tokio, BanksClientError, ProgramTest}, + solana_sdk::{ + instruction::InstructionError, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + transaction::{Transaction, TransactionError}, + }, + spl_token_interface::state::{account::Account, mint::Mint, multisig::Multisig}, + std::mem::size_of, }; -use spl_token_interface::state::{account::Account, mint::Mint, multisig::Multisig}; -use std::mem::size_of; #[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] diff --git a/package.json b/package.json index e336c22..539ad9d 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,15 @@ "rust:publish": "zx ./scripts/rust/publish.mjs", "rust:semver": "cargo semver-checks", "p-token:build": "zx ./scripts/rust/build-sbf.mjs p-token", + "p-token:format": "zx ./scripts/rust/format.mjs p-token", + "p-token:lint": "zx ./scripts/rust/lint.mjs p-token", "p-token:test": "zx ./scripts/rust/test.mjs p-token", "fixtures:clean": "zx ./scripts/rust/fixtures.mjs clean", "fixtures:generate": "zx ./scripts/rust/fixtures.mjs generate", - "fixtures:run": "zx ./scripts/rust/fixtures.mjs run" + "fixtures:run": "zx ./scripts/rust/fixtures.mjs run", + "interface:format": "zx ./scripts/rust/format.mjs interface", + "interface:lint": "zx ./scripts/rust/lint.mjs interface" + }, "devDependencies": { "@codama/renderers-js": "^1.2.7", From 4c467485a467542f343d8ccbdf8349486e3ca6dc Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Wed, 19 Mar 2025 10:51:46 +0000 Subject: [PATCH 322/335] p-token: Add error logging (#41) * Add fixtures test script * Add error logging * Update pinocchio dependencies * Fix formatting --- Cargo.lock | 28 +++++--------- interface/Cargo.toml | 4 +- interface/src/error.rs | 71 +++++++++++++++++++++++++++++++++++- p-token/Cargo.toml | 4 +- p-token/src/entrypoint.rs | 24 +++++++++--- p-token/src/processor/mod.rs | 8 ++-- package.json | 1 - 7 files changed, 105 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bcdc955..3ff8bc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2805,31 +2805,21 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinocchio" -version = "0.7.1" -source = "git+https://github.com/febo/pinocchio.git?branch=febo%2Fclose-unstable#246a026bb74c501ba83ea18201000e56c097cb0d" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2281a8e9e947c480ce0b64e2d6c6349d72890ba5db6503d5568edf96f304cba9" [[package]] name = "pinocchio-log" -version = "0.3.0" -source = "git+https://github.com/febo/pinocchio.git?branch=febo%2Fclose-unstable#246a026bb74c501ba83ea18201000e56c097cb0d" -dependencies = [ - "pinocchio-log-macro", -] - -[[package]] -name = "pinocchio-log-macro" -version = "0.3.0" -source = "git+https://github.com/febo/pinocchio.git?branch=febo%2Fclose-unstable#246a026bb74c501ba83ea18201000e56c097cb0d" -dependencies = [ - "quote", - "regex", - "syn 1.0.109", -] +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89f8ffd986174cefe59448295a004aaf70c3605f30de066f42d27b06188f267" [[package]] name = "pinocchio-pubkey" -version = "0.2.2" -source = "git+https://github.com/febo/pinocchio.git?branch=febo%2Fclose-unstable#246a026bb74c501ba83ea18201000e56c097cb0d" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c8cd934ccaf7915d19049275f77c8888860a2792102a5d9f0b8eafbf670f6a8" dependencies = [ "five8_const", "pinocchio", diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 69118d0..8d6703f 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -12,8 +12,8 @@ readme = "./README.md" crate-type = ["rlib"] [dependencies] -pinocchio = { version = "0.7", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } -pinocchio-pubkey = { version = "0.2", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } +pinocchio = "0.8" +pinocchio-pubkey = "0.2" [dev-dependencies] strum = "0.27" diff --git a/interface/src/error.rs b/interface/src/error.rs index 68b669e..33d3bbb 100644 --- a/interface/src/error.rs +++ b/interface/src/error.rs @@ -1,6 +1,6 @@ //! Error types -use pinocchio::program_error::ProgramError; +use pinocchio::program_error::{ProgramError, ToStr}; /// Errors that may be returned by the Token program. #[derive(Clone, Debug, Eq, PartialEq)] @@ -59,3 +59,72 @@ impl From for ProgramError { ProgramError::Custom(e as u32) } } + +impl ToStr for TokenError { + fn to_str(&self) -> &'static str + where + E: 'static + ToStr + TryFrom, + { + match self { + TokenError::NotRentExempt => "Error: Lamport balance below rent-exempt threshold", + TokenError::InsufficientFunds => "Error: insufficient funds", + TokenError::InvalidMint => "Error: Invalid Mint", + TokenError::MintMismatch => "Error: Account not associated with this Mint", + TokenError::OwnerMismatch => "Error: owner does not match", + TokenError::FixedSupply => "Error: the total supply of this token is fixed", + TokenError::AlreadyInUse => "Error: account or token already in use", + TokenError::InvalidNumberOfProvidedSigners => { + "Error: Invalid number of provided signers" + } + TokenError::InvalidNumberOfRequiredSigners => { + "Error: Invalid number of required signers" + } + TokenError::UninitializedState => "Error: State is uninitialized", + TokenError::NativeNotSupported => "Error: Instruction does not support native tokens", + TokenError::NonNativeHasBalance => { + "Error: Non-native account can only be closed if its balance is zero" + } + TokenError::InvalidInstruction => "Error: Invalid instruction", + TokenError::InvalidState => "Error: Invalid account state for operation", + TokenError::Overflow => "Error: Operation overflowed", + TokenError::AuthorityTypeNotSupported => { + "Error: Account does not support specified authority type" + } + TokenError::MintCannotFreeze => "Error: This token mint cannot freeze accounts", + TokenError::AccountFrozen => "Error: Account is frozen", + TokenError::MintDecimalsMismatch => "Error: decimals different from the Mint decimals", + TokenError::NonNativeNotSupported => { + "Error: Instruction does not support non-native tokens" + } + } + } +} + +impl TryFrom for TokenError { + type Error = ProgramError; + fn try_from(value: u32) -> Result { + match value { + 0 => Ok(TokenError::NotRentExempt), + 1 => Ok(TokenError::InsufficientFunds), + 2 => Ok(TokenError::InvalidMint), + 3 => Ok(TokenError::MintMismatch), + 4 => Ok(TokenError::OwnerMismatch), + 5 => Ok(TokenError::FixedSupply), + 6 => Ok(TokenError::AlreadyInUse), + 7 => Ok(TokenError::InvalidNumberOfProvidedSigners), + 8 => Ok(TokenError::InvalidNumberOfRequiredSigners), + 9 => Ok(TokenError::UninitializedState), + 10 => Ok(TokenError::NativeNotSupported), + 11 => Ok(TokenError::NonNativeHasBalance), + 12 => Ok(TokenError::InvalidInstruction), + 13 => Ok(TokenError::InvalidState), + 14 => Ok(TokenError::Overflow), + 15 => Ok(TokenError::AuthorityTypeNotSupported), + 16 => Ok(TokenError::MintCannotFreeze), + 17 => Ok(TokenError::AccountFrozen), + 18 => Ok(TokenError::MintDecimalsMismatch), + 19 => Ok(TokenError::NonNativeNotSupported), + _ => Err(ProgramError::InvalidArgument), + } + } +} diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index bfb6a41..99026a9 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -15,8 +15,8 @@ crate-type = ["cdylib"] logging = [] [dependencies] -pinocchio = { version = "0.7", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } -pinocchio-log = { version = "0.3", git = "https://github.com/febo/pinocchio.git", branch = "febo/close-unstable" } +pinocchio = "0.8" +pinocchio-log = { version = "0.4", default-features = false } spl-token-interface = { version = "^0", path = "../interface" } [dev-dependencies] diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 1422c67..599442d 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -1,9 +1,13 @@ use { crate::processor::*, pinocchio::{ - account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint, - program_error::ProgramError, pubkey::Pubkey, ProgramResult, + account_info::AccountInfo, + default_panic_handler, no_allocator, program_entrypoint, + program_error::{ProgramError, ToStr}, + pubkey::Pubkey, + ProgramResult, }, + spl_token_interface::error::TokenError, }; program_entrypoint!(process_instruction); @@ -12,6 +16,12 @@ no_allocator!(); // Use the default panic handler. default_panic_handler!(); +/// Log an error. +#[cold] +fn log_error(error: &ProgramError) { + pinocchio::log::sol_log(error.to_str::()); +} + /// Process an instruction. /// /// In the first stage, the entrypoint checks the discriminator of the @@ -29,15 +39,17 @@ pub fn process_instruction( return Err(ProgramError::InvalidInstructionData); }; - if *discriminator == 255 { + let result = if *discriminator == 255 { // 255 - Batch #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Batch"); - return process_batch(accounts, remaining); - } + process_batch(accounts, remaining) + } else { + inner_process_instruction(accounts, instruction_data) + }; - inner_process_instruction(accounts, instruction_data) + result.inspect_err(log_error) } /// Process a "regular" instruction. diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index a2ba93a..8d4132a 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -74,10 +74,10 @@ const MAX_FORMATTED_DIGITS: usize = u8::MAX as usize + 2; /// Checks that the account is owned by the expected program. #[inline(always)] fn check_account_owner(account_info: &AccountInfo) -> ProgramResult { - if &TOKEN_PROGRAM_ID != account_info.owner() { - Err(ProgramError::IncorrectProgramId) - } else { + if account_info.is_owned_by(&TOKEN_PROGRAM_ID) { Ok(()) + } else { + Err(ProgramError::IncorrectProgramId) } } @@ -98,7 +98,7 @@ fn validate_owner( } if owner_account_info.data_len() == Multisig::LEN - && owner_account_info.owner() == &TOKEN_PROGRAM_ID + && owner_account_info.is_owned_by(&TOKEN_PROGRAM_ID) { // SAFETY: the caller guarantees that there are no mutable borrows of // `owner_account_info` account data and the `load` validates that the diff --git a/package.json b/package.json index 539ad9d..c77ef06 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "fixtures:run": "zx ./scripts/rust/fixtures.mjs run", "interface:format": "zx ./scripts/rust/format.mjs interface", "interface:lint": "zx ./scripts/rust/lint.mjs interface" - }, "devDependencies": { "@codama/renderers-js": "^1.2.7", From ef92ca0a07b49b1295b493c2adaaf754a820e7b3 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Wed, 19 Mar 2025 16:17:18 +0000 Subject: [PATCH 323/335] interface: Add `no_std` attribute (#42) * Update dependencies * Add nostd attribute * Use nostd panic handler --- Cargo.lock | 12 ++++++------ interface/Cargo.toml | 2 +- interface/src/lib.rs | 2 ++ p-token/src/entrypoint.rs | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ff8bc0..2b3e95a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,18 +1336,18 @@ dependencies = [ [[package]] name = "five8_const" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" dependencies = [ "five8_core", ] [[package]] name = "five8_core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" +checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" [[package]] name = "flate2" @@ -2817,9 +2817,9 @@ checksum = "f89f8ffd986174cefe59448295a004aaf70c3605f30de066f42d27b06188f267" [[package]] name = "pinocchio-pubkey" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c8cd934ccaf7915d19049275f77c8888860a2792102a5d9f0b8eafbf670f6a8" +checksum = "0c6b20fcebc172c3cd3f54114b0241b48fa8e30893ced2eb4927aaba5e3a0ba5" dependencies = [ "five8_const", "pinocchio", diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 8d6703f..3413bd8 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -13,7 +13,7 @@ crate-type = ["rlib"] [dependencies] pinocchio = "0.8" -pinocchio-pubkey = "0.2" +pinocchio-pubkey = "0.2.4" [dev-dependencies] strum = "0.27" diff --git a/interface/src/lib.rs b/interface/src/lib.rs index 9622a25..f07b0df 100644 --- a/interface/src/lib.rs +++ b/interface/src/lib.rs @@ -1,3 +1,5 @@ +#![no_std] + pub mod error; pub mod instruction; pub mod native_mint; diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 599442d..6b7b3f4 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -2,7 +2,7 @@ use { crate::processor::*, pinocchio::{ account_info::AccountInfo, - default_panic_handler, no_allocator, program_entrypoint, + no_allocator, nostd_panic_handler, program_entrypoint, program_error::{ProgramError, ToStr}, pubkey::Pubkey, ProgramResult, @@ -13,8 +13,8 @@ use { program_entrypoint!(process_instruction); // Do not allocate memory. no_allocator!(); -// Use the default panic handler. -default_panic_handler!(); +// Use the no_std panic handler. +nostd_panic_handler!(); /// Log an error. #[cold] From b503b243d4ff211f27c670cf5c26adeb1f23d729 Mon Sep 17 00:00:00 2001 From: Jon C Date: Mon, 24 Mar 2025 22:48:57 +0100 Subject: [PATCH 324/335] CI: Fix semver checks on publish (#44) * CI: Fix semver checks to use a script #### Problem The semver checks step during publish is broken because it's simply passing in the folder, but there's some additional work needed to decompose it into a manifest path. #### Summary of changes Similar to many other repos, add a semver script which will pull out the manifest given a path. * Do it differently * Use pinocchio style * Install things consistently * Make publish depend on semver check * Add back version options (and fix inputs.crate) --- .github/workflows/publish-rust.yml | 59 +++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish-rust.yml b/.github/workflows/publish-rust.yml index ecbf986..1383406 100644 --- a/.github/workflows/publish-rust.yml +++ b/.github/workflows/publish-rust.yml @@ -22,6 +22,15 @@ on: - patch - minor - major + - rc + - beta + - alpha + - release + - version + version: + description: Version (used with level "version") + required: false + type: string dry_run: description: Dry run required: true @@ -50,11 +59,6 @@ jobs: cargo-cache-key: cargo-test-publish-${{ inputs.package_path }} cargo-cache-fallback-key: cargo-test-publish - - name: Install cargo-audit - uses: taiki-e/install-action@v2 - with: - tool: cargo-semver-checks - - name: Format run: pnpm zx ./scripts/rust/format.mjs "${{ inputs.package_path }}" @@ -67,13 +71,40 @@ jobs: - name: Test run: pnpm zx ./scripts/rust/test.mjs "${{ inputs.package_path }}" + semver: + name: Check Semver + runs-on: ubuntu-latest + steps: + - name: Git checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-publish-semver-${{ inputs.package_path }} + cargo-cache-fallback-key: cargo-publish-semver + + - name: Install cargo-semver-checks + uses: taiki-e/install-action@v2 + with: + tool: cargo-semver-checks,cargo-release + + - name: Set Version + run: | + if [ "${{ inputs.level }}" == "version" ]; then + LEVEL=${{ inputs.version }} + else + LEVEL=${{ inputs.level }} + fi + cargo release $LEVEL --manifest-path " ${{ inputs.package_path }}/Cargo.toml" --no-tag --no-publish --no-push --no-confirm --execute + - name: Check semver - run: pnpm rust:semver ${{ inputs.package_path }} --release-type ${{ inputs.level }} + run: pnpm rust:semver --manifest-path "${{ inputs.package_path }}/Cargo.toml" publish: name: Publish Rust Crate runs-on: ubuntu-latest - needs: test + needs: [test, semver] permissions: contents: write steps: @@ -89,8 +120,10 @@ jobs: cargo-cache-key: cargo-publish-${{ inputs.package_path }} cargo-cache-fallback-key: cargo-publish - - name: Install Cargo Release - run: which cargo-release || cargo install cargo-release + - name: Install cargo-release + uses: taiki-e/install-action@v2 + with: + tool: cargo-release - name: Ensure CARGO_REGISTRY_TOKEN variable is set env: @@ -111,13 +144,19 @@ jobs: env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} run: | + if [ "${{ inputs.level }}" == "version" ]; then + LEVEL=${{ inputs.version }} + else + LEVEL=${{ inputs.level }} + fi + if [ "${{ inputs.dry_run }}" == "true" ]; then OPTIONS="--dry-run" else OPTIONS="" fi - pnpm rust:publish "${{ inputs.package_path }}" "${{ inputs.level }}" $OPTIONS + pnpm rust:publish "${{ inputs.package_path }}" $LEVEL $OPTIONS - name: Generate a changelog if: github.event.inputs.create_release == 'true' From 7e343e7a059338ed34accb351ce87133ebea7669 Mon Sep 17 00:00:00 2001 From: Jon C Date: Mon, 24 Mar 2025 22:57:23 +0100 Subject: [PATCH 325/335] CI: Remove space in package path (#45) #### Problem There's an extra space in the manifest path, causing the publish job to fail. #### Summary of changes Remove it --- .github/workflows/publish-rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-rust.yml b/.github/workflows/publish-rust.yml index 1383406..41cfb77 100644 --- a/.github/workflows/publish-rust.yml +++ b/.github/workflows/publish-rust.yml @@ -96,7 +96,7 @@ jobs: else LEVEL=${{ inputs.level }} fi - cargo release $LEVEL --manifest-path " ${{ inputs.package_path }}/Cargo.toml" --no-tag --no-publish --no-push --no-confirm --execute + cargo release $LEVEL --manifest-path "${{ inputs.package_path }}/Cargo.toml" --no-tag --no-publish --no-push --no-confirm --execute - name: Check semver run: pnpm rust:semver --manifest-path "${{ inputs.package_path }}/Cargo.toml" From eaef45ac07a2b789bbe50066f8f82a6c1cc38550 Mon Sep 17 00:00:00 2001 From: Jon C Date: Mon, 24 Mar 2025 23:15:39 +0100 Subject: [PATCH 326/335] CI: Set git author / email before bump (#46) #### Problem cargo-release requires git identification to be set, even if it won't be used. #### Summary of changes Set the name and email. --- .github/workflows/publish-rust.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/publish-rust.yml b/.github/workflows/publish-rust.yml index 41cfb77..fbe4f69 100644 --- a/.github/workflows/publish-rust.yml +++ b/.github/workflows/publish-rust.yml @@ -89,6 +89,11 @@ jobs: with: tool: cargo-semver-checks,cargo-release + - name: Set Git Author (required for cargo-release) + run: | + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + - name: Set Version run: | if [ "${{ inputs.level }}" == "version" ]; then From 1f61242183ea9b43d37b47a1b4f745eb1beb32de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 22:26:01 +0000 Subject: [PATCH 327/335] Publish spl-token v8.0.0 --- Cargo.lock | 32 ++++++++++++++++---------------- program/Cargo.toml | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b3e95a..6fa65c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6882,6 +6882,21 @@ dependencies = [ [[package]] name = "spl-token" version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token" +version = "8.0.0" dependencies = [ "arrayref", "bytemuck", @@ -6912,21 +6927,6 @@ dependencies = [ "thiserror 2.0.11", ] -[[package]] -name = "spl-token" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" -dependencies = [ - "arrayref", - "bytemuck", - "num-derive", - "num-traits", - "num_enum", - "solana-program", - "thiserror 1.0.69", -] - [[package]] name = "spl-token-2022" version = "7.0.0" @@ -6944,7 +6944,7 @@ dependencies = [ "spl-elgamal-registry", "spl-memo", "spl-pod", - "spl-token 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 7.0.0", "spl-token-confidential-transfer-ciphertext-arithmetic", "spl-token-confidential-transfer-proof-extraction", "spl-token-confidential-transfer-proof-generation", diff --git a/program/Cargo.toml b/program/Cargo.toml index 3b5e041..817d57d 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spl-token" -version = "7.0.0" +version = "8.0.0" description = "Solana Program Library Token" authors = { workspace = true} repository = { workspace = true} From 299ac7ed10a393e4818d7de1562c8f75e4deaa84 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Tue, 25 Mar 2025 17:35:42 +0000 Subject: [PATCH 328/335] p-token: Tweaks to processors (#47) Tweaks to processors --- p-token/src/entrypoint.rs | 42 +++++++++---------- p-token/src/processor/amount_to_ui_amount.rs | 1 - p-token/src/processor/initialize_multisig2.rs | 1 - p-token/src/processor/ui_amount_to_amount.rs | 1 - .../src/processor/withdraw_excess_lamports.rs | 1 - 5 files changed, 21 insertions(+), 25 deletions(-) diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 6b7b3f4..343014e 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -110,6 +110,13 @@ pub(crate) fn inner_process_instruction( process_mint_to(accounts, instruction_data) } + // 8 - Burn + 8 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: Burn"); + + process_burn(accounts, instruction_data) + } // 9 - CloseAccount 9 => { #[cfg(feature = "logging")] @@ -117,6 +124,20 @@ pub(crate) fn inner_process_instruction( process_close_account(accounts) } + // 12 - TransferChecked + 12 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: TransferChecked"); + + process_transfer_checked(accounts, instruction_data) + } + // 15 - BurnChecked + 15 => { + #[cfg(feature = "logging")] + pinocchio::msg!("Instruction: BurnChecked"); + + process_burn_checked(accounts, instruction_data) + } // 16 - InitializeAccount2 16 => { #[cfg(feature = "logging")] @@ -182,13 +203,6 @@ fn inner_process_remaining_instruction( process_set_authority(accounts, instruction_data) } - // 8 - Burn - 8 => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: Burn"); - - process_burn(accounts, instruction_data) - } // 10 - FreezeAccount 10 => { #[cfg(feature = "logging")] @@ -203,13 +217,6 @@ fn inner_process_remaining_instruction( process_thaw_account(accounts) } - // 12 - TransferChecked - 12 => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: TransferChecked"); - - process_transfer_checked(accounts, instruction_data) - } // 13 - ApproveChecked 13 => { #[cfg(feature = "logging")] @@ -224,13 +231,6 @@ fn inner_process_remaining_instruction( process_mint_to_checked(accounts, instruction_data) } - // 15 - BurnChecked - 15 => { - #[cfg(feature = "logging")] - pinocchio::msg!("Instruction: BurnChecked"); - - process_burn_checked(accounts, instruction_data) - } // 17 - SyncNative 17 => { #[cfg(feature = "logging")] diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 5f58bda..6d02d00 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -12,7 +12,6 @@ use { }, }; -#[inline(always)] pub fn process_amount_to_ui_amount( accounts: &[AccountInfo], instruction_data: &[u8], diff --git a/p-token/src/processor/initialize_multisig2.rs b/p-token/src/processor/initialize_multisig2.rs index 884decc..c5592a4 100644 --- a/p-token/src/processor/initialize_multisig2.rs +++ b/p-token/src/processor/initialize_multisig2.rs @@ -3,7 +3,6 @@ use { pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, }; -#[inline(always)] pub fn process_initialize_multisig2( accounts: &[AccountInfo], instruction_data: &[u8], diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index 879e5c0..b479d1b 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -11,7 +11,6 @@ use { }, }; -#[inline(always)] pub fn process_ui_amount_to_amount( accounts: &[AccountInfo], instruction_data: &[u8], diff --git a/p-token/src/processor/withdraw_excess_lamports.rs b/p-token/src/processor/withdraw_excess_lamports.rs index cf5ca0e..59d304a 100644 --- a/p-token/src/processor/withdraw_excess_lamports.rs +++ b/p-token/src/processor/withdraw_excess_lamports.rs @@ -12,7 +12,6 @@ use { }, }; -#[inline(always)] #[allow(clippy::arithmetic_side_effects)] pub fn process_withdraw_excess_lamports(accounts: &[AccountInfo]) -> ProgramResult { let [source_account_info, destination_info, authority_info, remaining @ ..] = accounts else { From 20a1b93d56a10f3a5526b3388010be769c948e62 Mon Sep 17 00:00:00 2001 From: Jon C Date: Mon, 7 Apr 2025 19:09:41 +0200 Subject: [PATCH 329/335] Audit: Update openssl to 0.10.72 (#49) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fa65c2..3fff9e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2642,9 +2642,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.70" +version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ "bitflags 2.8.0", "cfg-if", @@ -2674,9 +2674,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.105" +version = "0.9.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" dependencies = [ "cc", "libc", From 8aef2d2b8d88b49c8c3f7274c1b33e39476c61c9 Mon Sep 17 00:00:00 2001 From: Jon C Date: Thu, 10 Apr 2025 15:59:08 +0200 Subject: [PATCH 330/335] Audit: Update crossbeam-channel to 0.5.15 (#50) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3fff9e8..5fd0d52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -861,9 +861,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] From 25b0d8c16babd829cb7c63d31144f6241076a2a0 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Wed, 30 Apr 2025 12:25:40 +0100 Subject: [PATCH 331/335] p-token: Allow withdraw excess lamports from mint without authority (#51) * Add mint as authority test * Add tests * Fix test comment * Update test names --- .../src/processor/withdraw_excess_lamports.rs | 25 +- p-token/tests/withdraw_excess_lamports.rs | 379 ++++++++++++++++++ 2 files changed, 399 insertions(+), 5 deletions(-) diff --git a/p-token/src/processor/withdraw_excess_lamports.rs b/p-token/src/processor/withdraw_excess_lamports.rs index 59d304a..efe49f8 100644 --- a/p-token/src/processor/withdraw_excess_lamports.rs +++ b/p-token/src/processor/withdraw_excess_lamports.rs @@ -18,7 +18,7 @@ pub fn process_withdraw_excess_lamports(accounts: &[AccountInfo]) -> ProgramResu return Err(ProgramError::NotEnoughAccountKeys); }; - // SAFETY: single mutable borrow to `source_account_info` account data + // SAFETY: single immutable borrow to `source_account_info` account data let source_data = unsafe { source_account_info.borrow_data_unchecked() }; match source_data.len() { @@ -36,10 +36,25 @@ pub fn process_withdraw_excess_lamports(accounts: &[AccountInfo]) -> ProgramResu // SAFETY: `source_data` has the same length as `Mint`. let mint = unsafe { load::(source_data)? }; - if let Some(mint_authority) = mint.mint_authority() { - validate_owner(mint_authority, authority_info, remaining)?; - } else { - return Err(TokenError::AuthorityTypeNotSupported.into()); + match mint.mint_authority() { + Some(mint_authority) => { + validate_owner(mint_authority, authority_info, remaining)?; + } + None if source_account_info == authority_info => { + // Comparing whether the AccountInfo's "point" to the same account or + // not - this is a faster comparison since it just checks the internal + // raw pointer. + // + // This is a special case where there is no mint authority set but the mint + // account is the same as the authority account and, therefore, needs to be + // a signer. + if !authority_info.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + } + _ => { + return Err(TokenError::AuthorityTypeNotSupported.into()); + } } } Multisig::LEN => { diff --git a/p-token/tests/withdraw_excess_lamports.rs b/p-token/tests/withdraw_excess_lamports.rs index 3d41e2a..052ec42 100644 --- a/p-token/tests/withdraw_excess_lamports.rs +++ b/p-token/tests/withdraw_excess_lamports.rs @@ -8,6 +8,7 @@ use { solana_program_test::{tokio, BanksClientError, ProgramTest}, solana_sdk::{ instruction::InstructionError, + program_pack::Pack, pubkey::Pubkey, signature::{Keypair, Signer}, system_instruction, @@ -758,3 +759,381 @@ async fn fail_withdraw_excess_lamports_from_multisig_missing_signer(token_progra )) ); } + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pubkey) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given a mint authority, freeze authority and an account keypair. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + let mint_account = Keypair::new(); + let account_pubkey = mint_account.pubkey(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_mint( + &spl_token::ID, + &mint_account.pubkey(), + &mint_authority.pubkey(), + Some(&freeze_authority), + 0, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // And we initialize a mint account with excess lamports. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &mint_account.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &mint_account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(mint_account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // And we remove the mint authority. + + let mut set_authority_ix = spl_token::instruction::set_authority( + &spl_token::ID, + &mint_account.pubkey(), + None, + spl_token::instruction::AuthorityType::MintTokens, + &mint_authority.pubkey(), + &[&mint_authority.pubkey()], + ) + .unwrap(); + // Switches the program id to the token program. + set_authority_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[set_authority_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &mint_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(mint_account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Mint::unpack(&account.data).unwrap(); + + assert!(account.mint_authority.is_none()); + + // When we withdraw the excess lamports with no authority. + + let destination = Pubkey::new_unique(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &account_pubkey, + &destination, + &mint_account.pubkey(), + &[], + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &mint_account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Then the destination account has the excess lamports. + + let destination = context.banks_client.get_account(destination).await.unwrap(); + + assert!(destination.is_some()); + + let destination = destination.unwrap(); + assert_eq!(destination.lamports, excess_lamports); +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn fail_withdraw_excess_lamports_from_mint_with_authority_and_mint_as_signer( + token_program: Pubkey, +) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given a mint authority, freeze authority and an account keypair. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + let mint_account = Keypair::new(); + let account_pubkey = mint_account.pubkey(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_mint( + &spl_token::ID, + &mint_account.pubkey(), + &mint_authority.pubkey(), + Some(&freeze_authority), + 0, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // And we initialize a mint account with excess lamports. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &mint_account.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &mint_account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(mint_account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // When we try to withdraw the excess lamports with the mint as authority. + + let destination = Pubkey::new_unique(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &account_pubkey, + &destination, + &mint_account.pubkey(), + &[], + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &mint_account], + context.last_blockhash, + ); + let error = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err(); + + // Then we expect an error. + + assert_matches!( + error, + BanksClientError::TransactionError(TransactionError::InstructionError( + _, + InstructionError::Custom(4) // TokenError::OwnerMismatch + )) + ); +} + +#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] +#[tokio::test] +async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority_signer( + token_program: Pubkey, +) { + let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) + .start_with_context() + .await; + + let excess_lamports = 4_000_000_000_000; + + // Given a mint authority, freeze authority and an account keypair. + + let mint_authority = Keypair::new(); + let freeze_authority = Pubkey::new_unique(); + let mint_account = Keypair::new(); + let account_pubkey = mint_account.pubkey(); + + let account_size = size_of::(); + let rent = context.banks_client.get_rent().await.unwrap(); + + let mut initialize_ix = spl_token::instruction::initialize_mint( + &spl_token::ID, + &mint_account.pubkey(), + &mint_authority.pubkey(), + Some(&freeze_authority), + 0, + ) + .unwrap(); + // Switches the program id to the token program. + initialize_ix.program_id = token_program; + + // And we initialize a mint account with excess lamports. + + let instructions = vec![ + system_instruction::create_account( + &context.payer.pubkey(), + &mint_account.pubkey(), + rent.minimum_balance(account_size) + excess_lamports, + account_size as u64, + &token_program, + ), + initialize_ix, + ]; + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&context.payer.pubkey()), + &[&context.payer, &mint_account], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(mint_account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + assert_eq!( + account.lamports, + rent.minimum_balance(account_size) + excess_lamports + ); + + // And we remove the mint authority. + + let mut set_authority_ix = spl_token::instruction::set_authority( + &spl_token::ID, + &mint_account.pubkey(), + None, + spl_token::instruction::AuthorityType::MintTokens, + &mint_authority.pubkey(), + &[&mint_authority.pubkey()], + ) + .unwrap(); + // Switches the program id to the token program. + set_authority_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[set_authority_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &mint_authority], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + let account = context + .banks_client + .get_account(mint_account.pubkey()) + .await + .unwrap(); + + assert!(account.is_some()); + + let account = account.unwrap(); + let account = spl_token::state::Mint::unpack(&account.data).unwrap(); + + assert!(account.mint_authority.is_none()); + + // When we try to withdraw the excess lamports with the "old" mint authority. + + let destination = Pubkey::new_unique(); + + let mut withdraw_ix = spl_token_2022::instruction::withdraw_excess_lamports( + &spl_token_2022::ID, + &account_pubkey, + &destination, + &mint_authority.pubkey(), + &[], + ) + .unwrap(); + // Switches the program id to the token program. + withdraw_ix.program_id = token_program; + + let tx = Transaction::new_signed_with_payer( + &[withdraw_ix], + Some(&context.payer.pubkey()), + &[&context.payer, &mint_authority], + context.last_blockhash, + ); + let error = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err(); + + // Then we expect an error. + + assert_matches!( + error, + BanksClientError::TransactionError(TransactionError::InstructionError( + _, + InstructionError::Custom(15) // TokenError::AuthorityTypeNotSupported + )) + ); +} From feb11f8aa40a5ec245524d8cf959c6e19e26600f Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Wed, 30 Apr 2025 22:10:27 +0100 Subject: [PATCH 332/335] p-token: Clean-up test_case annotation (#53) * Add mint as authority test * Add tests * Fix test comment * Update test names * Remove test case annotation * Remove dependency --- Cargo.lock | 34 ------ p-token/Cargo.toml | 1 - p-token/tests/amount_to_ui_amount.rs | 9 +- p-token/tests/approve.rs | 13 ++- p-token/tests/approve_checked.rs | 15 ++- p-token/tests/batch.rs | 25 +++-- p-token/tests/burn.rs | 13 ++- p-token/tests/burn_checked.rs | 13 ++- p-token/tests/close_account.rs | 11 +- p-token/tests/freeze_account.rs | 12 +-- p-token/tests/initialize_account.rs | 11 +- p-token/tests/initialize_account2.rs | 11 +- p-token/tests/initialize_account3.rs | 11 +- p-token/tests/initialize_mint.rs | 9 +- p-token/tests/initialize_mint2.rs | 9 +- p-token/tests/initialize_multisig.rs | 9 +- p-token/tests/initialize_multisig2.rs | 9 +- p-token/tests/mint_to.rs | 12 +-- p-token/tests/mint_to_checked.rs | 12 +-- p-token/tests/revoke.rs | 15 ++- p-token/tests/set_authority.rs | 8 +- p-token/tests/thaw_account.rs | 14 ++- p-token/tests/transfer.rs | 15 ++- p-token/tests/transfer_checked.rs | 15 ++- p-token/tests/ui_amount_to_amount.rs | 9 +- p-token/tests/withdraw_excess_lamports.rs | 126 ++++++++-------------- 26 files changed, 161 insertions(+), 280 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5fd0d52..1fe57c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2838,7 +2838,6 @@ dependencies = [ "spl-token 4.0.2", "spl-token-2022", "spl-token-interface", - "test-case", ] [[package]] @@ -7312,39 +7311,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" -[[package]] -name = "test-case" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" -dependencies = [ - "test-case-macros", -] - -[[package]] -name = "test-case-core" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.96", -] - -[[package]] -name = "test-case-macros" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.96", - "test-case-core", -] - [[package]] name = "thiserror" version = "1.0.69" diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 99026a9..273916c 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -26,7 +26,6 @@ solana-program-test = "2.1" solana-sdk = "2.1" spl-token = { version="^4", features=["no-entrypoint"] } spl-token-2022 = { version="^7", features=["no-entrypoint"] } -test-case = "3.3.1" [lints] workspace = true diff --git a/p-token/tests/amount_to_ui_amount.rs b/p-token/tests/amount_to_ui_amount.rs index 6504605..55bbd39 100644 --- a/p-token/tests/amount_to_ui_amount.rs +++ b/p-token/tests/amount_to_ui_amount.rs @@ -6,9 +6,8 @@ use { solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn amount_to_ui_amount(token_program: Pubkey) { +async fn amount_to_ui_amount() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -22,15 +21,13 @@ async fn amount_to_ui_amount(token_program: Pubkey) { &mut context, mint_authority, Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); - let mut amount_to_ui_amount_ix = + let amount_to_ui_amount_ix = spl_token::instruction::amount_to_ui_amount(&spl_token::ID, &mint, 1000).unwrap(); - // Switches the program id to the token program. - amount_to_ui_amount_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[amount_to_ui_amount_ix], diff --git a/p-token/tests/approve.rs b/p-token/tests/approve.rs index b0ce007..78c22d4 100644 --- a/p-token/tests/approve.rs +++ b/p-token/tests/approve.rs @@ -11,9 +11,8 @@ use { }, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn approve(token_program: Pubkey) { +async fn approve() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -27,7 +26,7 @@ async fn approve(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -36,7 +35,8 @@ async fn approve(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + let account = + account::initialize(&mut context, &mint, &owner.pubkey(), &TOKEN_PROGRAM_ID).await; mint::mint( &mut context, @@ -44,7 +44,7 @@ async fn approve(token_program: Pubkey) { &account, &mint_authority, 100, - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -53,7 +53,7 @@ async fn approve(token_program: Pubkey) { let delegate = Pubkey::new_unique(); - let mut approve_ix = spl_token::instruction::approve( + let approve_ix = spl_token::instruction::approve( &spl_token::ID, &account, &delegate, @@ -62,7 +62,6 @@ async fn approve(token_program: Pubkey) { 50, ) .unwrap(); - approve_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[approve_ix], diff --git a/p-token/tests/approve_checked.rs b/p-token/tests/approve_checked.rs index 2080b15..7a70d92 100644 --- a/p-token/tests/approve_checked.rs +++ b/p-token/tests/approve_checked.rs @@ -11,9 +11,8 @@ use { }, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn approve_checked(token_program: Pubkey) { +async fn approve_checked() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -27,7 +26,7 @@ async fn approve_checked(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -36,7 +35,8 @@ async fn approve_checked(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + let account = + account::initialize(&mut context, &mint, &owner.pubkey(), &TOKEN_PROGRAM_ID).await; mint::mint( &mut context, @@ -44,7 +44,7 @@ async fn approve_checked(token_program: Pubkey) { &account, &mint_authority, 100, - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -53,8 +53,8 @@ async fn approve_checked(token_program: Pubkey) { let delegate = Pubkey::new_unique(); - let mut approve_ix = spl_token::instruction::approve_checked( - &spl_token::ID, + let approve_ix = spl_token::instruction::approve_checked( + &TOKEN_PROGRAM_ID, &account, &mint, &delegate, @@ -64,7 +64,6 @@ async fn approve_checked(token_program: Pubkey) { 4, ) .unwrap(); - approve_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[approve_ix], diff --git a/p-token/tests/batch.rs b/p-token/tests/batch.rs index 4c837c4..10ffac4 100644 --- a/p-token/tests/batch.rs +++ b/p-token/tests/batch.rs @@ -40,9 +40,8 @@ fn batch_instruction(instructions: Vec) -> Result(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_mint( + let initialize_ix = spl_token::instruction::initialize_mint( &spl_token::ID, &account.pubkey(), &mint_authority, @@ -39,8 +38,6 @@ async fn initialize_mint(token_program: Pubkey) { 0, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // When a new mint account is created and initialized. @@ -50,7 +47,7 @@ async fn initialize_mint(token_program: Pubkey) { &account.pubkey(), rent.minimum_balance(account_size), account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; diff --git a/p-token/tests/initialize_mint2.rs b/p-token/tests/initialize_mint2.rs index 819ba72..faa9651 100644 --- a/p-token/tests/initialize_mint2.rs +++ b/p-token/tests/initialize_mint2.rs @@ -15,9 +15,8 @@ use { std::mem::size_of, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn initialize_mint2(token_program: Pubkey) { +async fn initialize_mint2() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -31,7 +30,7 @@ async fn initialize_mint2(token_program: Pubkey) { let account_size = size_of::(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_mint2( + let initialize_ix = spl_token::instruction::initialize_mint2( &spl_token::ID, &account.pubkey(), &mint_authority, @@ -39,8 +38,6 @@ async fn initialize_mint2(token_program: Pubkey) { 0, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // When a new mint account is created and initialized. @@ -50,7 +47,7 @@ async fn initialize_mint2(token_program: Pubkey) { &account.pubkey(), rent.minimum_balance(account_size), account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; diff --git a/p-token/tests/initialize_multisig.rs b/p-token/tests/initialize_multisig.rs index 14e126a..a52ed9f 100644 --- a/p-token/tests/initialize_multisig.rs +++ b/p-token/tests/initialize_multisig.rs @@ -13,9 +13,8 @@ use { spl_token::state::Multisig, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn initialize_multisig(token_program: Pubkey) { +async fn initialize_multisig() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -30,15 +29,13 @@ async fn initialize_multisig(token_program: Pubkey) { let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_multisig( + let initialize_ix = spl_token::instruction::initialize_multisig( &spl_token::ID, &multisig.pubkey(), &signers, 2, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // When a new multisig account is created and initialized. @@ -48,7 +45,7 @@ async fn initialize_multisig(token_program: Pubkey) { &multisig.pubkey(), rent.minimum_balance(Multisig::LEN), Multisig::LEN as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; diff --git a/p-token/tests/initialize_multisig2.rs b/p-token/tests/initialize_multisig2.rs index b8de8fe..19a7bd3 100644 --- a/p-token/tests/initialize_multisig2.rs +++ b/p-token/tests/initialize_multisig2.rs @@ -13,9 +13,8 @@ use { spl_token::state::Multisig, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn initialize_multisig2(token_program: Pubkey) { +async fn initialize_multisig2() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -30,15 +29,13 @@ async fn initialize_multisig2(token_program: Pubkey) { let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_multisig2( + let initialize_ix = spl_token::instruction::initialize_multisig2( &spl_token::ID, &multisig.pubkey(), &signers, 2, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // When a new multisig account is created and initialized. @@ -48,7 +45,7 @@ async fn initialize_multisig2(token_program: Pubkey) { &multisig.pubkey(), rent.minimum_balance(Multisig::LEN), Multisig::LEN as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; diff --git a/p-token/tests/mint_to.rs b/p-token/tests/mint_to.rs index fdabcc8..cb576ee 100644 --- a/p-token/tests/mint_to.rs +++ b/p-token/tests/mint_to.rs @@ -11,9 +11,8 @@ use { }, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn mint_to(token_program: Pubkey) { +async fn mint_to() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -27,7 +26,7 @@ async fn mint_to(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -36,11 +35,12 @@ async fn mint_to(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + let account = + account::initialize(&mut context, &mint, &owner.pubkey(), &TOKEN_PROGRAM_ID).await; // When we mint tokens to it. - let mut mint_ix = spl_token::instruction::mint_to( + let mint_ix = spl_token::instruction::mint_to( &spl_token::ID, &mint, &account, @@ -49,8 +49,6 @@ async fn mint_to(token_program: Pubkey) { 100, ) .unwrap(); - // Switches the program id to the token program. - mint_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[mint_ix], diff --git a/p-token/tests/mint_to_checked.rs b/p-token/tests/mint_to_checked.rs index 2a3b69c..579ad1a 100644 --- a/p-token/tests/mint_to_checked.rs +++ b/p-token/tests/mint_to_checked.rs @@ -11,9 +11,8 @@ use { }, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn mint_to_checked(token_program: Pubkey) { +async fn mint_to_checked() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -27,7 +26,7 @@ async fn mint_to_checked(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -36,11 +35,12 @@ async fn mint_to_checked(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + let account = + account::initialize(&mut context, &mint, &owner.pubkey(), &TOKEN_PROGRAM_ID).await; // When we mint tokens to it. - let mut mint_ix = spl_token::instruction::mint_to_checked( + let mint_ix = spl_token::instruction::mint_to_checked( &spl_token::ID, &mint, &account, @@ -50,8 +50,6 @@ async fn mint_to_checked(token_program: Pubkey) { 4, ) .unwrap(); - // Switches the program id to the token program. - mint_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[mint_ix], diff --git a/p-token/tests/revoke.rs b/p-token/tests/revoke.rs index 43fd34c..ee2433f 100644 --- a/p-token/tests/revoke.rs +++ b/p-token/tests/revoke.rs @@ -11,9 +11,8 @@ use { }, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn revoke(token_program: Pubkey) { +async fn revoke() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -27,7 +26,7 @@ async fn revoke(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -36,7 +35,8 @@ async fn revoke(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + let account = + account::initialize(&mut context, &mint, &owner.pubkey(), &TOKEN_PROGRAM_ID).await; mint::mint( &mut context, @@ -44,7 +44,7 @@ async fn revoke(token_program: Pubkey) { &account, &mint_authority, 100, - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -59,15 +59,14 @@ async fn revoke(token_program: Pubkey) { &delegate, &owner, 50, - &token_program, + &TOKEN_PROGRAM_ID, ) .await; // When we revoke the delegation. - let mut revoke_ix = + let revoke_ix = spl_token::instruction::revoke(&spl_token::ID, &account, &owner.pubkey(), &[]).unwrap(); - revoke_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[revoke_ix], diff --git a/p-token/tests/set_authority.rs b/p-token/tests/set_authority.rs index c96ee2b..f813736 100644 --- a/p-token/tests/set_authority.rs +++ b/p-token/tests/set_authority.rs @@ -13,9 +13,8 @@ use { spl_token::instruction::AuthorityType, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn set_authority(token_program: Pubkey) { +async fn set_authority() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -29,7 +28,7 @@ async fn set_authority(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority.pubkey()), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -38,7 +37,7 @@ async fn set_authority(token_program: Pubkey) { let new_authority = Pubkey::new_unique(); - let mut set_authority_ix = spl_token::instruction::set_authority( + let set_authority_ix = spl_token::instruction::set_authority( &spl_token::ID, &mint, Some(&new_authority), @@ -47,7 +46,6 @@ async fn set_authority(token_program: Pubkey) { &[], ) .unwrap(); - set_authority_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[set_authority_ix], diff --git a/p-token/tests/thaw_account.rs b/p-token/tests/thaw_account.rs index be99451..bb70a3a 100644 --- a/p-token/tests/thaw_account.rs +++ b/p-token/tests/thaw_account.rs @@ -5,16 +5,14 @@ use { solana_program_test::{tokio, ProgramTest}, solana_sdk::{ program_pack::Pack, - pubkey::Pubkey, signature::{Keypair, Signer}, transaction::Transaction, }, spl_token::state::AccountState, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn thaw_account(token_program: Pubkey) { +async fn thaw_account() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -28,7 +26,7 @@ async fn thaw_account(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority.pubkey()), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -37,7 +35,8 @@ async fn thaw_account(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + let account = + account::initialize(&mut context, &mint, &owner.pubkey(), &TOKEN_PROGRAM_ID).await; let token_account = context.banks_client.get_account(account).await.unwrap(); assert!(token_account.is_some()); @@ -47,13 +46,13 @@ async fn thaw_account(token_program: Pubkey) { &account, &mint, &freeze_authority, - &token_program, + &TOKEN_PROGRAM_ID, ) .await; // When we thaw the account. - let mut thaw_account_ix = spl_token::instruction::thaw_account( + let thaw_account_ix = spl_token::instruction::thaw_account( &spl_token::ID, &account, &mint, @@ -61,7 +60,6 @@ async fn thaw_account(token_program: Pubkey) { &[], ) .unwrap(); - thaw_account_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[thaw_account_ix], diff --git a/p-token/tests/transfer.rs b/p-token/tests/transfer.rs index de6bd5e..c414654 100644 --- a/p-token/tests/transfer.rs +++ b/p-token/tests/transfer.rs @@ -11,9 +11,8 @@ use { }, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn transfer(token_program: Pubkey) { +async fn transfer() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -27,7 +26,7 @@ async fn transfer(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -36,7 +35,8 @@ async fn transfer(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + let account = + account::initialize(&mut context, &mint, &owner.pubkey(), &TOKEN_PROGRAM_ID).await; mint::mint( &mut context, @@ -44,7 +44,7 @@ async fn transfer(token_program: Pubkey) { &account, &mint_authority, 100, - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -54,9 +54,9 @@ async fn transfer(token_program: Pubkey) { let destination = Pubkey::new_unique(); let destination_account = - account::initialize(&mut context, &mint, &destination, &token_program).await; + account::initialize(&mut context, &mint, &destination, &TOKEN_PROGRAM_ID).await; - let mut transfer_ix = spl_token::instruction::transfer( + let transfer_ix = spl_token::instruction::transfer( &spl_token::ID, &account, &destination_account, @@ -65,7 +65,6 @@ async fn transfer(token_program: Pubkey) { 100, ) .unwrap(); - transfer_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[transfer_ix], diff --git a/p-token/tests/transfer_checked.rs b/p-token/tests/transfer_checked.rs index 9a5ca0c..11f1d13 100644 --- a/p-token/tests/transfer_checked.rs +++ b/p-token/tests/transfer_checked.rs @@ -11,9 +11,8 @@ use { }, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn transfer_checked(token_program: Pubkey) { +async fn transfer_checked() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -27,7 +26,7 @@ async fn transfer_checked(token_program: Pubkey) { &mut context, mint_authority.pubkey(), Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -36,7 +35,8 @@ async fn transfer_checked(token_program: Pubkey) { let owner = Keypair::new(); - let account = account::initialize(&mut context, &mint, &owner.pubkey(), &token_program).await; + let account = + account::initialize(&mut context, &mint, &owner.pubkey(), &TOKEN_PROGRAM_ID).await; mint::mint( &mut context, @@ -44,7 +44,7 @@ async fn transfer_checked(token_program: Pubkey) { &account, &mint_authority, 100, - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -54,9 +54,9 @@ async fn transfer_checked(token_program: Pubkey) { let destination = Pubkey::new_unique(); let destination_account = - account::initialize(&mut context, &mint, &destination, &token_program).await; + account::initialize(&mut context, &mint, &destination, &TOKEN_PROGRAM_ID).await; - let mut transfer_ix = spl_token::instruction::transfer_checked( + let transfer_ix = spl_token::instruction::transfer_checked( &spl_token::ID, &account, &mint, @@ -67,7 +67,6 @@ async fn transfer_checked(token_program: Pubkey) { 4, ) .unwrap(); - transfer_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[transfer_ix], diff --git a/p-token/tests/ui_amount_to_amount.rs b/p-token/tests/ui_amount_to_amount.rs index 2fc9a9d..d0059d3 100644 --- a/p-token/tests/ui_amount_to_amount.rs +++ b/p-token/tests/ui_amount_to_amount.rs @@ -6,9 +6,8 @@ use { solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::Transaction}, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn ui_amount_to_amount(token_program: Pubkey) { +async fn ui_amount_to_amount() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -22,15 +21,13 @@ async fn ui_amount_to_amount(token_program: Pubkey) { &mut context, mint_authority, Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); - let mut ui_amount_to_amount_ix = + let ui_amount_to_amount_ix = spl_token::instruction::ui_amount_to_amount(&spl_token::ID, &mint, "1000.00").unwrap(); - // Switches the program id to the token program. - ui_amount_to_amount_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[ui_amount_to_amount_ix], diff --git a/p-token/tests/withdraw_excess_lamports.rs b/p-token/tests/withdraw_excess_lamports.rs index 052ec42..dc39630 100644 --- a/p-token/tests/withdraw_excess_lamports.rs +++ b/p-token/tests/withdraw_excess_lamports.rs @@ -18,9 +18,8 @@ use { std::mem::size_of, }; -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn withdraw_excess_lamports_from_mint(token_program: Pubkey) { +async fn withdraw_excess_lamports_from_mint() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -37,7 +36,7 @@ async fn withdraw_excess_lamports_from_mint(token_program: Pubkey) { let account_size = size_of::(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_mint( + let initialize_ix = spl_token::instruction::initialize_mint( &spl_token::ID, &account.pubkey(), &mint_authority.pubkey(), @@ -45,8 +44,6 @@ async fn withdraw_excess_lamports_from_mint(token_program: Pubkey) { 0, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // And we initialize a mint account with excess lamports. @@ -56,7 +53,7 @@ async fn withdraw_excess_lamports_from_mint(token_program: Pubkey) { &account.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -96,7 +93,7 @@ async fn withdraw_excess_lamports_from_mint(token_program: Pubkey) { ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -116,9 +113,8 @@ async fn withdraw_excess_lamports_from_mint(token_program: Pubkey) { assert_eq!(destination.lamports, excess_lamports); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn withdraw_excess_lamports_from_account(token_program: Pubkey) { +async fn withdraw_excess_lamports_from_account() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -134,7 +130,7 @@ async fn withdraw_excess_lamports_from_account(token_program: Pubkey) { &mut context, mint_authority, Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -148,15 +144,13 @@ async fn withdraw_excess_lamports_from_account(token_program: Pubkey) { let account_size = size_of::(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_account( + let initialize_ix = spl_token::instruction::initialize_account( &spl_token::ID, &account.pubkey(), &mint, &owner.pubkey(), ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // When a new mint account is created and initialized. @@ -166,7 +160,7 @@ async fn withdraw_excess_lamports_from_account(token_program: Pubkey) { &account.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -206,7 +200,7 @@ async fn withdraw_excess_lamports_from_account(token_program: Pubkey) { ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -226,9 +220,8 @@ async fn withdraw_excess_lamports_from_account(token_program: Pubkey) { assert_eq!(destination.lamports, excess_lamports); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn withdraw_excess_lamports_from_multisig(token_program: Pubkey) { +async fn withdraw_excess_lamports_from_multisig() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -249,15 +242,13 @@ async fn withdraw_excess_lamports_from_multisig(token_program: Pubkey) { let rent = context.banks_client.get_rent().await.unwrap(); let account_size = size_of::(); - let mut initialize_ix = spl_token::instruction::initialize_multisig( + let initialize_ix = spl_token::instruction::initialize_multisig( &spl_token::ID, &multisig.pubkey(), &signers, 3, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // And we initialize the multisig account. @@ -267,7 +258,7 @@ async fn withdraw_excess_lamports_from_multisig(token_program: Pubkey) { &multisig.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -307,7 +298,7 @@ async fn withdraw_excess_lamports_from_multisig(token_program: Pubkey) { ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -327,9 +318,8 @@ async fn withdraw_excess_lamports_from_multisig(token_program: Pubkey) { assert_eq!(destination.lamports, excess_lamports); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn fail_withdraw_excess_lamports_from_mint_wrong_authority(token_program: Pubkey) { +async fn fail_withdraw_excess_lamports_from_mint_wrong_authority() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -346,7 +336,7 @@ async fn fail_withdraw_excess_lamports_from_mint_wrong_authority(token_program: let account_size = size_of::(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_mint( + let initialize_ix = spl_token::instruction::initialize_mint( &spl_token::ID, &account.pubkey(), &mint_authority.pubkey(), @@ -354,8 +344,6 @@ async fn fail_withdraw_excess_lamports_from_mint_wrong_authority(token_program: 0, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // And we initialize a mint account with excess lamports. @@ -365,7 +353,7 @@ async fn fail_withdraw_excess_lamports_from_mint_wrong_authority(token_program: &account.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -406,7 +394,7 @@ async fn fail_withdraw_excess_lamports_from_mint_wrong_authority(token_program: ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -431,9 +419,8 @@ async fn fail_withdraw_excess_lamports_from_mint_wrong_authority(token_program: ); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn fail_withdraw_excess_lamports_from_account_wrong_authority(token_program: Pubkey) { +async fn fail_withdraw_excess_lamports_from_account_wrong_authority() { let mut context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -449,7 +436,7 @@ async fn fail_withdraw_excess_lamports_from_account_wrong_authority(token_progra &mut context, mint_authority, Some(freeze_authority), - &token_program, + &TOKEN_PROGRAM_ID, ) .await .unwrap(); @@ -463,15 +450,13 @@ async fn fail_withdraw_excess_lamports_from_account_wrong_authority(token_progra let account_size = size_of::(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_account( + let initialize_ix = spl_token::instruction::initialize_account( &spl_token::ID, &account.pubkey(), &mint, &owner.pubkey(), ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // When a new mint account is created and initialized. @@ -481,7 +466,7 @@ async fn fail_withdraw_excess_lamports_from_account_wrong_authority(token_progra &account.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -522,7 +507,7 @@ async fn fail_withdraw_excess_lamports_from_account_wrong_authority(token_progra ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -547,9 +532,8 @@ async fn fail_withdraw_excess_lamports_from_account_wrong_authority(token_progra ); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn fail_withdraw_excess_lamports_from_multisig_wrong_authority(token_program: Pubkey) { +async fn fail_withdraw_excess_lamports_from_multisig_wrong_authority() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -570,15 +554,13 @@ async fn fail_withdraw_excess_lamports_from_multisig_wrong_authority(token_progr let rent = context.banks_client.get_rent().await.unwrap(); let account_size = size_of::(); - let mut initialize_ix = spl_token::instruction::initialize_multisig( + let initialize_ix = spl_token::instruction::initialize_multisig( &spl_token::ID, &multisig.pubkey(), &signers, 3, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // And we initialize the multisig account. @@ -588,7 +570,7 @@ async fn fail_withdraw_excess_lamports_from_multisig_wrong_authority(token_progr &multisig.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -629,7 +611,7 @@ async fn fail_withdraw_excess_lamports_from_multisig_wrong_authority(token_progr ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -654,9 +636,8 @@ async fn fail_withdraw_excess_lamports_from_multisig_wrong_authority(token_progr ); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn fail_withdraw_excess_lamports_from_multisig_missing_signer(token_program: Pubkey) { +async fn fail_withdraw_excess_lamports_from_multisig_missing_signer() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -677,15 +658,13 @@ async fn fail_withdraw_excess_lamports_from_multisig_missing_signer(token_progra let rent = context.banks_client.get_rent().await.unwrap(); let account_size = size_of::(); - let mut initialize_ix = spl_token::instruction::initialize_multisig( + let initialize_ix = spl_token::instruction::initialize_multisig( &spl_token::ID, &multisig.pubkey(), &signers, 3, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // And we initialize the multisig account. @@ -695,7 +674,7 @@ async fn fail_withdraw_excess_lamports_from_multisig_missing_signer(token_progra &multisig.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -735,7 +714,7 @@ async fn fail_withdraw_excess_lamports_from_multisig_missing_signer(token_progra ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -760,9 +739,8 @@ async fn fail_withdraw_excess_lamports_from_multisig_missing_signer(token_progra ); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pubkey) { +async fn withdraw_excess_lamports_from_mint_with_no_authority() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -779,7 +757,7 @@ async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pub let account_size = size_of::(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_mint( + let initialize_ix = spl_token::instruction::initialize_mint( &spl_token::ID, &mint_account.pubkey(), &mint_authority.pubkey(), @@ -787,8 +765,6 @@ async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pub 0, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // And we initialize a mint account with excess lamports. @@ -798,7 +774,7 @@ async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pub &mint_account.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -827,7 +803,7 @@ async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pub // And we remove the mint authority. - let mut set_authority_ix = spl_token::instruction::set_authority( + let set_authority_ix = spl_token::instruction::set_authority( &spl_token::ID, &mint_account.pubkey(), None, @@ -836,8 +812,6 @@ async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pub &[&mint_authority.pubkey()], ) .unwrap(); - // Switches the program id to the token program. - set_authority_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[set_authority_ix], @@ -873,7 +847,7 @@ async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pub ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -893,11 +867,8 @@ async fn withdraw_excess_lamports_from_mint_with_no_authority(token_program: Pub assert_eq!(destination.lamports, excess_lamports); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn fail_withdraw_excess_lamports_from_mint_with_authority_and_mint_as_signer( - token_program: Pubkey, -) { +async fn fail_withdraw_excess_lamports_from_mint_with_authority_and_mint_as_signer() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -914,7 +885,7 @@ async fn fail_withdraw_excess_lamports_from_mint_with_authority_and_mint_as_sign let account_size = size_of::(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_mint( + let initialize_ix = spl_token::instruction::initialize_mint( &spl_token::ID, &mint_account.pubkey(), &mint_authority.pubkey(), @@ -922,8 +893,6 @@ async fn fail_withdraw_excess_lamports_from_mint_with_authority_and_mint_as_sign 0, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // And we initialize a mint account with excess lamports. @@ -933,7 +902,7 @@ async fn fail_withdraw_excess_lamports_from_mint_with_authority_and_mint_as_sign &mint_account.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -973,7 +942,7 @@ async fn fail_withdraw_excess_lamports_from_mint_with_authority_and_mint_as_sign ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], @@ -998,11 +967,8 @@ async fn fail_withdraw_excess_lamports_from_mint_with_authority_and_mint_as_sign ); } -#[test_case::test_case(TOKEN_PROGRAM_ID ; "p-token")] #[tokio::test] -async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority_signer( - token_program: Pubkey, -) { +async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority_signer() { let context = ProgramTest::new("pinocchio_token_program", TOKEN_PROGRAM_ID, None) .start_with_context() .await; @@ -1019,7 +985,7 @@ async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority let account_size = size_of::(); let rent = context.banks_client.get_rent().await.unwrap(); - let mut initialize_ix = spl_token::instruction::initialize_mint( + let initialize_ix = spl_token::instruction::initialize_mint( &spl_token::ID, &mint_account.pubkey(), &mint_authority.pubkey(), @@ -1027,8 +993,6 @@ async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority 0, ) .unwrap(); - // Switches the program id to the token program. - initialize_ix.program_id = token_program; // And we initialize a mint account with excess lamports. @@ -1038,7 +1002,7 @@ async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority &mint_account.pubkey(), rent.minimum_balance(account_size) + excess_lamports, account_size as u64, - &token_program, + &TOKEN_PROGRAM_ID, ), initialize_ix, ]; @@ -1067,7 +1031,7 @@ async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority // And we remove the mint authority. - let mut set_authority_ix = spl_token::instruction::set_authority( + let set_authority_ix = spl_token::instruction::set_authority( &spl_token::ID, &mint_account.pubkey(), None, @@ -1076,8 +1040,6 @@ async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority &[&mint_authority.pubkey()], ) .unwrap(); - // Switches the program id to the token program. - set_authority_ix.program_id = token_program; let tx = Transaction::new_signed_with_payer( &[set_authority_ix], @@ -1113,7 +1075,7 @@ async fn fail_withdraw_excess_lamports_from_mint_with_no_authority_and_authority ) .unwrap(); // Switches the program id to the token program. - withdraw_ix.program_id = token_program; + withdraw_ix.program_id = TOKEN_PROGRAM_ID; let tx = Transaction::new_signed_with_payer( &[withdraw_ix], From 001b6a256ca825799fba945ec82257e357ea23f4 Mon Sep 17 00:00:00 2001 From: Jon C Date: Fri, 2 May 2025 16:27:09 +0200 Subject: [PATCH 333/335] dependabot: Auto-approve PRs (#54) #### Problem Now that PRs require approval, dependabot PRs don't automatically merge. #### Summary of changes Add a step to approve the PR. --- .github/workflows/dependabot-auto-merge.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 76cbcfb..639402d 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -15,3 +15,8 @@ jobs: env: PR_URL: ${{ github.event.pull_request.html_url }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Approve + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 4c3fabd685e30b27bbc8f5d515626177dd720a02 Mon Sep 17 00:00:00 2001 From: Fernando Otero Date: Mon, 5 May 2025 15:29:56 +0100 Subject: [PATCH 334/335] p-token: Fix error codes (#52) * Fix error codes * Fix formatting * Add validation on load * Fix formatting * Fix typo * Relax instruction data length check * Another relax length check * More relax instruction data length check * Move account validation * Fix rent exempt check * Update pinocchio reference * Improve coption validation * Streamline initialize check * Add unpack helpers --- Cargo.lock | 4 +- interface/Cargo.toml | 4 +- interface/src/instruction.rs | 6 +- interface/src/state/account.rs | 22 +++++-- interface/src/state/account_state.rs | 15 +++++ interface/src/state/mint.rs | 14 +++-- interface/src/state/mod.rs | 6 +- interface/src/state/multisig.rs | 16 ++++-- p-token/Cargo.toml | 2 +- p-token/src/entrypoint.rs | 8 +-- p-token/src/processor/amount_to_ui_amount.rs | 8 +-- p-token/src/processor/approve.rs | 10 +--- p-token/src/processor/approve_checked.rs | 17 ++---- p-token/src/processor/batch.rs | 5 +- p-token/src/processor/burn.rs | 10 +--- p-token/src/processor/burn_checked.rs | 17 ++---- p-token/src/processor/initialize_account2.rs | 14 +++-- p-token/src/processor/initialize_account3.rs | 14 +++-- .../processor/initialize_immutable_owner.rs | 2 +- p-token/src/processor/initialize_multisig.rs | 5 +- p-token/src/processor/initialize_multisig2.rs | 6 +- p-token/src/processor/mint_to.rs | 10 +--- p-token/src/processor/mint_to_checked.rs | 17 ++---- p-token/src/processor/mod.rs | 31 ++++++++++ p-token/src/processor/revoke.rs | 12 +++- p-token/src/processor/set_authority.rs | 32 ++++++----- p-token/src/processor/shared/approve.rs | 2 +- p-token/src/processor/shared/burn.rs | 13 ++--- .../processor/shared/initialize_account.rs | 4 +- .../src/processor/shared/initialize_mint.rs | 57 ++++++++++--------- .../processor/shared/initialize_multisig.rs | 2 +- p-token/src/processor/shared/mint_to.rs | 2 +- .../processor/shared/toggle_account_state.rs | 6 +- p-token/src/processor/shared/transfer.rs | 4 +- p-token/src/processor/transfer.rs | 10 +--- p-token/src/processor/transfer_checked.rs | 17 ++---- p-token/src/processor/ui_amount_to_amount.rs | 3 +- 37 files changed, 229 insertions(+), 198 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1fe57c4..fd109c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2805,9 +2805,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinocchio" -version = "0.8.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2281a8e9e947c480ce0b64e2d6c6349d72890ba5db6503d5568edf96f304cba9" +checksum = "7c33b58567c11b07749cefbb8320ac023f3387c57807aeb8e3b1262501b6e9f0" [[package]] name = "pinocchio-log" diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 3413bd8..4906302 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -12,8 +12,8 @@ readme = "./README.md" crate-type = ["rlib"] [dependencies] -pinocchio = "0.8" -pinocchio-pubkey = "0.2.4" +pinocchio = "0.8.4" +pinocchio-pubkey = "0.2" [dev-dependencies] strum = "0.27" diff --git a/interface/src/instruction.rs b/interface/src/instruction.rs index 9b1e36c..7ebcc07 100644 --- a/interface/src/instruction.rs +++ b/interface/src/instruction.rs @@ -1,6 +1,6 @@ //! Instruction types. -use pinocchio::program_error::ProgramError; +use {crate::error::TokenError, pinocchio::program_error::ProgramError}; /// Instructions supported by the token program. #[repr(u8)] @@ -531,7 +531,7 @@ impl TryFrom for TokenInstruction { match value { // SAFETY: `value` is guaranteed to be in the range of the enum variants. 0..=24 | 38 | 255 => Ok(unsafe { core::mem::transmute::(value) }), - _ => Err(ProgramError::InvalidInstructionData), + _ => Err(TokenError::InvalidInstruction.into()), } } } @@ -559,7 +559,7 @@ impl TryFrom for AuthorityType { match value { // SAFETY: `value` is guaranteed to be in the range of the enum variants. 0..=3 => Ok(unsafe { core::mem::transmute::(value) }), - _ => Err(ProgramError::InvalidInstructionData), + _ => Err(TokenError::InvalidInstruction.into()), } } } diff --git a/interface/src/state/account.rs b/interface/src/state/account.rs index ba8b145..a734cb1 100644 --- a/interface/src/state/account.rs +++ b/interface/src/state/account.rs @@ -1,6 +1,6 @@ use { super::{account_state::AccountState, COption, Initializable, Transmutable}, - pinocchio::pubkey::Pubkey, + pinocchio::{program_error::ProgramError, pubkey::Pubkey}, }; /// Incinerator address. @@ -27,7 +27,7 @@ pub struct Account { delegate: COption, /// The account's state. - pub state: AccountState, + state: u8, /// Indicates whether this account represents a native token or not. is_native: [u8; 4], @@ -46,6 +46,16 @@ pub struct Account { } impl Account { + #[inline(always)] + pub fn set_account_state(&mut self, state: AccountState) { + self.state = state as u8; + } + + #[inline(always)] + pub fn account_state(&self) -> Result { + AccountState::try_from(self.state) + } + #[inline(always)] pub fn set_amount(&mut self, amount: u64) { self.amount = amount.to_le_bytes(); @@ -131,8 +141,8 @@ impl Account { } #[inline(always)] - pub fn is_frozen(&self) -> bool { - self.state == AccountState::Frozen + pub fn is_frozen(&self) -> Result { + AccountState::try_from(self.state).map(|state| state == AccountState::Frozen) } #[inline(always)] @@ -147,7 +157,7 @@ impl Transmutable for Account { impl Initializable for Account { #[inline(always)] - fn is_initialized(&self) -> bool { - self.state != AccountState::Uninitialized + fn is_initialized(&self) -> Result { + AccountState::try_from(self.state).map(|state| state != AccountState::Uninitialized) } } diff --git a/interface/src/state/account_state.rs b/interface/src/state/account_state.rs index 6747757..b10572c 100644 --- a/interface/src/state/account_state.rs +++ b/interface/src/state/account_state.rs @@ -1,3 +1,5 @@ +use pinocchio::program_error::ProgramError; + #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum AccountState { @@ -13,3 +15,16 @@ pub enum AccountState { /// this account. Frozen, } + +impl TryFrom for AccountState { + type Error = ProgramError; + + #[inline(always)] + fn try_from(value: u8) -> Result { + match value { + // SAFETY: `value` is guaranteed to be in the range of the enum variants. + 0..=2 => Ok(unsafe { core::mem::transmute::(value) }), + _ => Err(ProgramError::InvalidAccountData), + } + } +} diff --git a/interface/src/state/mint.rs b/interface/src/state/mint.rs index 18c7bc5..489c9ef 100644 --- a/interface/src/state/mint.rs +++ b/interface/src/state/mint.rs @@ -1,6 +1,6 @@ use { super::{COption, Initializable, Transmutable}, - pinocchio::pubkey::Pubkey, + pinocchio::{program_error::ProgramError, pubkey::Pubkey}, }; /// Internal representation of a mint data. @@ -10,7 +10,7 @@ pub struct Mint { /// be provided during mint creation. If no mint authority is present /// then the mint has a fixed supply and no further tokens may be /// minted. - pub mint_authority: COption, + mint_authority: COption, /// Total supply of tokens. supply: [u8; 8], @@ -24,7 +24,7 @@ pub struct Mint { // Indicates whether the freeze authority is present or not. //freeze_authority_option: [u8; 4], /// Optional authority to freeze token accounts. - pub freeze_authority: COption, + freeze_authority: COption, } impl Mint { @@ -91,7 +91,11 @@ impl Transmutable for Mint { impl Initializable for Mint { #[inline(always)] - fn is_initialized(&self) -> bool { - self.is_initialized == 1 + fn is_initialized(&self) -> Result { + match self.is_initialized { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(ProgramError::InvalidAccountData), + } } } diff --git a/interface/src/state/mod.rs b/interface/src/state/mod.rs index 61128ff..67de793 100644 --- a/interface/src/state/mod.rs +++ b/interface/src/state/mod.rs @@ -23,7 +23,7 @@ pub trait Transmutable { /// Trait to represent a type that can be initialized. pub trait Initializable { /// Return `true` if the object is initialized. - fn is_initialized(&self) -> bool; + fn is_initialized(&self) -> Result; } /// Return a reference for an initialized `T` from the given bytes. @@ -35,7 +35,7 @@ pub trait Initializable { pub unsafe fn load(bytes: &[u8]) -> Result<&T, ProgramError> { load_unchecked(bytes).and_then(|t: &T| { // checks if the data is initialized - if t.is_initialized() { + if t.is_initialized()? { Ok(t) } else { Err(ProgramError::UninitializedAccount) @@ -69,7 +69,7 @@ pub unsafe fn load_mut( ) -> Result<&mut T, ProgramError> { load_mut_unchecked(bytes).and_then(|t: &mut T| { // checks if the data is initialized - if t.is_initialized() { + if t.is_initialized()? { Ok(t) } else { Err(ProgramError::UninitializedAccount) diff --git a/interface/src/state/multisig.rs b/interface/src/state/multisig.rs index caa08fb..b579c3d 100644 --- a/interface/src/state/multisig.rs +++ b/interface/src/state/multisig.rs @@ -1,6 +1,6 @@ use { super::{Initializable, Transmutable}, - pinocchio::pubkey::Pubkey, + pinocchio::{program_error::ProgramError, pubkey::Pubkey}, }; /// Minimum number of multisignature signers (min N) @@ -18,10 +18,10 @@ pub struct Multisig { /// Number of valid signers. pub n: u8, - /// Is `true` if this structure has been initialized + /// Is `true` if this structure has been initialized. is_initialized: u8, - /// Signer public keys + /// Signer public keys. pub signers: [Pubkey; MAX_SIGNERS as usize], } @@ -39,13 +39,17 @@ impl Multisig { } impl Transmutable for Multisig { - /// The length of the `Mint` account data. + /// The length of the `Multisig` account data. const LEN: usize = core::mem::size_of::(); } impl Initializable for Multisig { #[inline(always)] - fn is_initialized(&self) -> bool { - self.is_initialized == 1 + fn is_initialized(&self) -> Result { + match self.is_initialized { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(ProgramError::InvalidAccountData), + } } } diff --git a/p-token/Cargo.toml b/p-token/Cargo.toml index 273916c..8b9fce7 100644 --- a/p-token/Cargo.toml +++ b/p-token/Cargo.toml @@ -15,7 +15,7 @@ crate-type = ["cdylib"] logging = [] [dependencies] -pinocchio = "0.8" +pinocchio = "0.8.4" pinocchio-log = { version = "0.4", default-features = false } spl-token-interface = { version = "^0", path = "../interface" } diff --git a/p-token/src/entrypoint.rs b/p-token/src/entrypoint.rs index 343014e..290e26a 100644 --- a/p-token/src/entrypoint.rs +++ b/p-token/src/entrypoint.rs @@ -36,7 +36,7 @@ pub fn process_instruction( instruction_data: &[u8], ) -> ProgramResult { let [discriminator, remaining @ ..] = instruction_data else { - return Err(ProgramError::InvalidInstructionData); + return Err(TokenError::InvalidInstruction.into()); }; let result = if *discriminator == 255 { @@ -78,7 +78,7 @@ pub(crate) fn inner_process_instruction( instruction_data: &[u8], ) -> ProgramResult { let [discriminator, instruction_data @ ..] = instruction_data else { - return Err(ProgramError::InvalidInstructionData); + return Err(TokenError::InvalidInstruction.into()); }; match *discriminator { @@ -194,7 +194,7 @@ fn inner_process_remaining_instruction( #[cfg(feature = "logging")] pinocchio::msg!("Instruction: Revoke"); - process_revoke(accounts, instruction_data) + process_revoke(accounts) } // 6 - SetAuthority 6 => { @@ -280,6 +280,6 @@ fn inner_process_remaining_instruction( process_withdraw_excess_lamports(accounts) } - _ => Err(ProgramError::InvalidInstructionData), + _ => Err(TokenError::InvalidInstruction.into()), } } diff --git a/p-token/src/processor/amount_to_ui_amount.rs b/p-token/src/processor/amount_to_ui_amount.rs index 6d02d00..d0aff7e 100644 --- a/p-token/src/processor/amount_to_ui_amount.rs +++ b/p-token/src/processor/amount_to_ui_amount.rs @@ -1,5 +1,5 @@ use { - super::{check_account_owner, MAX_FORMATTED_DIGITS}, + super::{check_account_owner, unpack_amount, MAX_FORMATTED_DIGITS}, core::str::from_utf8_unchecked, pinocchio::{ account_info::AccountInfo, program::set_return_data, program_error::ProgramError, @@ -16,11 +16,7 @@ pub fn process_amount_to_ui_amount( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let amount = u64::from_le_bytes( - instruction_data - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + let amount = unpack_amount(instruction_data)?; let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; diff --git a/p-token/src/processor/approve.rs b/p-token/src/processor/approve.rs index a24846f..3564918 100644 --- a/p-token/src/processor/approve.rs +++ b/p-token/src/processor/approve.rs @@ -1,15 +1,11 @@ use { - super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + super::{shared, unpack_amount}, + pinocchio::{account_info::AccountInfo, ProgramResult}, }; #[inline(always)] pub fn process_approve(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - let amount = u64::from_le_bytes( - instruction_data - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + let amount = unpack_amount(instruction_data)?; shared::approve::process_approve(accounts, amount, None) } diff --git a/p-token/src/processor/approve_checked.rs b/p-token/src/processor/approve_checked.rs index c2a2185..5e62c21 100644 --- a/p-token/src/processor/approve_checked.rs +++ b/p-token/src/processor/approve_checked.rs @@ -1,20 +1,11 @@ use { - super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + super::{shared, unpack_amount_and_decimals}, + pinocchio::{account_info::AccountInfo, ProgramResult}, }; #[inline(always)] pub fn process_approve_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - // expected u64 (8) + u8 (1) - let (amount, decimals) = if instruction_data.len() == 9 { - let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); - ( - u64::from_le_bytes(amount.try_into().unwrap()), - decimals.first().copied(), - ) - } else { - return Err(ProgramError::InvalidInstructionData); - }; + let (amount, decimals) = unpack_amount_and_decimals(instruction_data)?; - shared::approve::process_approve(accounts, amount, decimals) + shared::approve::process_approve(accounts, amount, Some(decimals)) } diff --git a/p-token/src/processor/batch.rs b/p-token/src/processor/batch.rs index 501f08b..1a95f82 100644 --- a/p-token/src/processor/batch.rs +++ b/p-token/src/processor/batch.rs @@ -1,6 +1,7 @@ use { crate::entrypoint::inner_process_instruction, pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + spl_token_interface::error::TokenError, }; /// The size of the batch instruction header. @@ -17,7 +18,7 @@ pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8]) if instruction_data.len() < IX_HEADER_SIZE { // The instruction data must have at least two bytes. - return Err(ProgramError::InvalidInstructionData); + return Err(TokenError::InvalidInstruction.into()); } // SAFETY: The instruction data is guaranteed to have at least two bytes @@ -27,7 +28,7 @@ pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8]) let data_offset = IX_HEADER_SIZE + unsafe { *instruction_data.get_unchecked(1) as usize }; if instruction_data.len() < data_offset || data_offset == IX_HEADER_SIZE { - return Err(ProgramError::InvalidInstructionData); + return Err(TokenError::InvalidInstruction.into()); } if accounts.len() < expected_accounts { diff --git a/p-token/src/processor/burn.rs b/p-token/src/processor/burn.rs index e964696..966de6c 100644 --- a/p-token/src/processor/burn.rs +++ b/p-token/src/processor/burn.rs @@ -1,15 +1,11 @@ use { - super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + super::{shared, unpack_amount}, + pinocchio::{account_info::AccountInfo, ProgramResult}, }; #[inline(always)] pub fn process_burn(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - let amount = u64::from_le_bytes( - instruction_data - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + let amount = unpack_amount(instruction_data)?; shared::burn::process_burn(accounts, amount, None) } diff --git a/p-token/src/processor/burn_checked.rs b/p-token/src/processor/burn_checked.rs index 5501c0f..b068213 100644 --- a/p-token/src/processor/burn_checked.rs +++ b/p-token/src/processor/burn_checked.rs @@ -1,20 +1,11 @@ use { - super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + super::{shared, unpack_amount_and_decimals}, + pinocchio::{account_info::AccountInfo, ProgramResult}, }; #[inline(always)] pub fn process_burn_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - // expected u64 (8) + u8 (1) - let (amount, decimals) = if instruction_data.len() == 9 { - let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); - ( - u64::from_le_bytes(amount.try_into().unwrap()), - decimals.first().copied(), - ) - } else { - return Err(ProgramError::InvalidInstructionData); - }; + let (amount, decimals) = unpack_amount_and_decimals(instruction_data)?; - shared::burn::process_burn(accounts, amount, decimals) + shared::burn::process_burn(accounts, amount, Some(decimals)) } diff --git a/p-token/src/processor/initialize_account2.rs b/p-token/src/processor/initialize_account2.rs index 04a1bf8..d2b30d2 100644 --- a/p-token/src/processor/initialize_account2.rs +++ b/p-token/src/processor/initialize_account2.rs @@ -1,8 +1,11 @@ use { super::shared, pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, + account_info::AccountInfo, + pubkey::{Pubkey, PUBKEY_BYTES}, + ProgramResult, }, + spl_token_interface::error::TokenError, }; #[inline(always)] @@ -10,9 +13,12 @@ pub fn process_initialize_account2( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let owner: &Pubkey = instruction_data - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?; + let owner = if instruction_data.len() >= PUBKEY_BYTES { + // SAFETY: The minimum size of the instruction data is `PUBKEY_BYTES` bytes. + unsafe { &*(instruction_data.as_ptr() as *const Pubkey) } + } else { + return Err(TokenError::InvalidInstruction.into()); + }; shared::initialize_account::process_initialize_account(accounts, Some(owner), true) } diff --git a/p-token/src/processor/initialize_account3.rs b/p-token/src/processor/initialize_account3.rs index 0863681..8e86d9e 100644 --- a/p-token/src/processor/initialize_account3.rs +++ b/p-token/src/processor/initialize_account3.rs @@ -1,8 +1,11 @@ use { super::shared, pinocchio::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult, + account_info::AccountInfo, + pubkey::{Pubkey, PUBKEY_BYTES}, + ProgramResult, }, + spl_token_interface::error::TokenError, }; #[inline(always)] @@ -10,9 +13,12 @@ pub fn process_initialize_account3( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let owner: &Pubkey = instruction_data - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?; + let owner = if instruction_data.len() >= PUBKEY_BYTES { + // SAFETY: The minimum size of the instruction data is `PUBKEY_BYTES` bytes. + unsafe { &*(instruction_data.as_ptr() as *const Pubkey) } + } else { + return Err(TokenError::InvalidInstruction.into()); + }; shared::initialize_account::process_initialize_account(accounts, Some(owner), false) } diff --git a/p-token/src/processor/initialize_immutable_owner.rs b/p-token/src/processor/initialize_immutable_owner.rs index 60bd26a..4c48519 100644 --- a/p-token/src/processor/initialize_immutable_owner.rs +++ b/p-token/src/processor/initialize_immutable_owner.rs @@ -13,7 +13,7 @@ pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramRe // SAFETY: single immutable borrow to `token_account_info` account data. let account = unsafe { load_unchecked::(token_account_info.borrow_data_unchecked())? }; - if account.is_initialized() { + if account.is_initialized()? { return Err(TokenError::AlreadyInUse.into()); } // Please upgrade to SPL Token 2022 for immutable owner support. diff --git a/p-token/src/processor/initialize_multisig.rs b/p-token/src/processor/initialize_multisig.rs index b175a3b..183c2af 100644 --- a/p-token/src/processor/initialize_multisig.rs +++ b/p-token/src/processor/initialize_multisig.rs @@ -1,6 +1,7 @@ use { super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + pinocchio::{account_info::AccountInfo, ProgramResult}, + spl_token_interface::error::TokenError, }; #[inline(always)] @@ -10,7 +11,7 @@ pub fn process_initialize_multisig( ) -> ProgramResult { let m = instruction_data .first() - .ok_or(ProgramError::InvalidInstructionData)?; + .ok_or(TokenError::InvalidInstruction)?; shared::initialize_multisig::process_initialize_multisig(accounts, *m, true) } diff --git a/p-token/src/processor/initialize_multisig2.rs b/p-token/src/processor/initialize_multisig2.rs index c5592a4..377aa20 100644 --- a/p-token/src/processor/initialize_multisig2.rs +++ b/p-token/src/processor/initialize_multisig2.rs @@ -1,6 +1,7 @@ use { super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + pinocchio::{account_info::AccountInfo, ProgramResult}, + spl_token_interface::error::TokenError, }; pub fn process_initialize_multisig2( @@ -9,6 +10,7 @@ pub fn process_initialize_multisig2( ) -> ProgramResult { let m = instruction_data .first() - .ok_or(ProgramError::InvalidInstructionData)?; + .ok_or(TokenError::InvalidInstruction)?; + shared::initialize_multisig::process_initialize_multisig(accounts, *m, false) } diff --git a/p-token/src/processor/mint_to.rs b/p-token/src/processor/mint_to.rs index ca22c60..6d1305b 100644 --- a/p-token/src/processor/mint_to.rs +++ b/p-token/src/processor/mint_to.rs @@ -1,15 +1,11 @@ use { - super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + super::{shared, unpack_amount}, + pinocchio::{account_info::AccountInfo, ProgramResult}, }; #[inline(always)] pub fn process_mint_to(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - let amount = u64::from_le_bytes( - instruction_data - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + let amount = unpack_amount(instruction_data)?; shared::mint_to::process_mint_to(accounts, amount, None) } diff --git a/p-token/src/processor/mint_to_checked.rs b/p-token/src/processor/mint_to_checked.rs index b7703bd..5255a56 100644 --- a/p-token/src/processor/mint_to_checked.rs +++ b/p-token/src/processor/mint_to_checked.rs @@ -1,20 +1,11 @@ use { - super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + super::{shared, unpack_amount_and_decimals}, + pinocchio::{account_info::AccountInfo, ProgramResult}, }; #[inline(always)] pub fn process_mint_to_checked(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - // expected u64 (8) + u8 (1) - let (amount, decimals) = if instruction_data.len() == 9 { - let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); - ( - u64::from_le_bytes(amount.try_into().unwrap()), - decimals.first().copied(), - ) - } else { - return Err(ProgramError::InvalidInstructionData); - }; + let (amount, decimals) = unpack_amount_and_decimals(instruction_data)?; - shared::mint_to::process_mint_to(accounts, amount, decimals) + shared::mint_to::process_mint_to(accounts, amount, Some(decimals)) } diff --git a/p-token/src/processor/mod.rs b/p-token/src/processor/mod.rs index 8d4132a..34d29c3 100644 --- a/p-token/src/processor/mod.rs +++ b/p-token/src/processor/mod.rs @@ -64,6 +64,9 @@ pub use { withdraw_excess_lamports::process_withdraw_excess_lamports, }; +/// Number of bytes in a `u64`. +const U64_BYTES: usize = core::mem::size_of::(); + /// Maximum number of digits in a formatted `u64`. /// /// The maximum number of digits is equal to the maximum number @@ -180,3 +183,31 @@ fn try_ui_amount_into_amount(ui_amount: &str, decimals: u8) -> Result Result { + // expected u64 (8) + if instruction_data.len() >= U64_BYTES { + // SAFETY: The minimum size of the instruction data is `U64_BYTES` bytes. + Ok(unsafe { u64::from_le_bytes(*(instruction_data.as_ptr() as *const [u8; U64_BYTES])) }) + } else { + Err(TokenError::InvalidInstruction) + } +} + +/// Unpacks a `u64` amount and an optional `u8` from the instruction data. +#[inline(always)] +const fn unpack_amount_and_decimals(instruction_data: &[u8]) -> Result<(u64, u8), TokenError> { + // expected u64 (8) + u8 (1) + if instruction_data.len() >= 9 { + let (amount, decimals) = instruction_data.split_at(U64_BYTES); + Ok(( + // SAFETY: The size of `amount` is `U64_BYTES` bytes. + unsafe { u64::from_le_bytes(*(amount.as_ptr() as *const [u8; U64_BYTES])) }, + decimals[0], + )) + } else { + Err(TokenError::InvalidInstruction) + } +} diff --git a/p-token/src/processor/revoke.rs b/p-token/src/processor/revoke.rs index 56ceba1..cc1b92d 100644 --- a/p-token/src/processor/revoke.rs +++ b/p-token/src/processor/revoke.rs @@ -8,8 +8,8 @@ use { }; #[inline(always)] -pub fn process_revoke(accounts: &[AccountInfo], _instruction_data: &[u8]) -> ProgramResult { - let [source_account_info, owner_info, remaining @ ..] = accounts else { +pub fn process_revoke(accounts: &[AccountInfo]) -> ProgramResult { + let [source_account_info, remaining @ ..] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; @@ -18,7 +18,13 @@ pub fn process_revoke(accounts: &[AccountInfo], _instruction_data: &[u8]) -> Pro let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; - if source_account.is_frozen() { + // Unpacking the remaining accounts to get the owner account at this point + // to maintain the same order as SPL Token. + let [owner_info, remaining @ ..] = remaining else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if source_account.is_frozen()? { return Err(TokenError::AccountFrozen.into()); } diff --git a/p-token/src/processor/set_authority.rs b/p-token/src/processor/set_authority.rs index 81a8ce3..38e4331 100644 --- a/p-token/src/processor/set_authority.rs +++ b/p-token/src/processor/set_authority.rs @@ -14,21 +14,23 @@ use { pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { // Validates the instruction data. - // SAFETY: The expected size of the instruction data is either 2 or 34 bytes: - // - authority_type (1 byte) - // - option + new_authority (1 byte + 32 bytes) - let (authority_type, new_authority) = unsafe { - match instruction_data.len() { - 2 if *instruction_data.get_unchecked(1) == 0 => ( - AuthorityType::try_from(*instruction_data.get_unchecked(0))?, - None, - ), - 34 if *instruction_data.get_unchecked(1) == 1 => ( - AuthorityType::try_from(*instruction_data.get_unchecked(0))?, - Some(&*(instruction_data.as_ptr().add(2) as *const Pubkey)), - ), - _ => return Err(ProgramError::InvalidInstructionData), + let (authority_type, new_authority) = if instruction_data.len() >= 2 { + // SAFETY: The expected size of the instruction data is either 2 or 34 bytes: + // - authority_type (1 byte) + // - option + new_authority (1 byte + 32 bytes) + unsafe { + let authority_type = AuthorityType::try_from(*instruction_data.get_unchecked(0))?; + let new_authority = if *instruction_data.get_unchecked(1) == 0 { + None + } else if *instruction_data.get_unchecked(1) == 1 && instruction_data.len() >= 34 { + Some(&*(instruction_data.as_ptr().add(2) as *const Pubkey)) + } else { + return Err(TokenError::InvalidInstruction.into()); + }; + (authority_type, new_authority) } + } else { + return Err(TokenError::InvalidInstruction.into()); }; // Validates the accounts. @@ -42,7 +44,7 @@ pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) // `load_mut` validates that the account is initialized. let account = unsafe { load_mut::(account_info.borrow_mut_data_unchecked())? }; - if account.is_frozen() { + if account.is_frozen()? { return Err(TokenError::AccountFrozen.into()); } diff --git a/p-token/src/processor/shared/approve.rs b/p-token/src/processor/shared/approve.rs index 520ccb8..d2fcaa0 100644 --- a/p-token/src/processor/shared/approve.rs +++ b/p-token/src/processor/shared/approve.rs @@ -51,7 +51,7 @@ pub fn process_approve( let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; - if source_account.is_frozen() { + if source_account.is_frozen()? { return Err(TokenError::AccountFrozen.into()); } diff --git a/p-token/src/processor/shared/burn.rs b/p-token/src/processor/shared/burn.rs index 6a3511e..f8f7215 100644 --- a/p-token/src/processor/shared/burn.rs +++ b/p-token/src/processor/shared/burn.rs @@ -21,8 +21,13 @@ pub fn process_burn( // `load_mut` validates that the account is initialized. let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; + // SAFETY: single mutable borrow to `mint_info` account data and + // `load_mut` validates that the mint is initialized; additionally, an + // account cannot be both a token account and a mint, so if duplicates are + // passed in, one of them will fail the `load_mut` check. + let mint = unsafe { load_mut::(mint_info.borrow_mut_data_unchecked())? }; - if source_account.is_frozen() { + if source_account.is_frozen()? { return Err(TokenError::AccountFrozen.into()); } if source_account.is_native() { @@ -36,12 +41,6 @@ pub fn process_burn( .checked_sub(amount) .ok_or(TokenError::InsufficientFunds)?; - // SAFETY: single mutable borrow to `mint_info` account data and - // `load_mut` validates that the mint is initialized; additionally, an - // account cannot be both a token account and a mint, so if duplicates are - // passed in, one of them will fail the `load_mut` check. - let mint = unsafe { load_mut::(mint_info.borrow_mut_data_unchecked())? }; - if mint_info.key() != &source_account.mint { return Err(TokenError::MintMismatch.into()); } diff --git a/p-token/src/processor/shared/initialize_account.rs b/p-token/src/processor/shared/initialize_account.rs index 897318d..7d3f858 100644 --- a/p-token/src/processor/shared/initialize_account.rs +++ b/p-token/src/processor/shared/initialize_account.rs @@ -62,7 +62,7 @@ pub fn process_initialize_account( let account = unsafe { load_mut_unchecked::(new_account_info.borrow_mut_data_unchecked())? }; - if account.is_initialized() { + if account.is_initialized()? { return Err(TokenError::AlreadyInUse.into()); } @@ -80,7 +80,7 @@ pub fn process_initialize_account( }; } - account.state = AccountState::Initialized; + account.set_account_state(AccountState::Initialized); account.mint = *mint_info.key(); account.owner = *owner; diff --git a/p-token/src/processor/shared/initialize_mint.rs b/p-token/src/processor/shared/initialize_mint.rs index d53f668..c7145d2 100644 --- a/p-token/src/processor/shared/initialize_mint.rs +++ b/p-token/src/processor/shared/initialize_mint.rs @@ -1,5 +1,4 @@ use { - core::mem::size_of, pinocchio::{ account_info::AccountInfo, program_error::ProgramError, @@ -21,24 +20,26 @@ pub fn process_initialize_mint( ) -> ProgramResult { // Validates the instruction data. - // SAFETY: The minimum size of the instruction data is either 34 or 66 bytes: - // - decimals (1 byte) - // - mint_authority (32 bytes) - // - option + freeze_authority (1 byte + 32 bytes) - let (decimals, mint_authority, freeze_authority) = unsafe { - match instruction_data.len() { - 34 if *instruction_data.get_unchecked(33) == 0 => ( - *instruction_data.get_unchecked(0), - &*(instruction_data.as_ptr().add(1) as *const Pubkey), - None, - ), - 66 if *instruction_data.get_unchecked(33) == 1 => ( - *instruction_data.get_unchecked(0), - &*(instruction_data.as_ptr().add(1) as *const Pubkey), - Some(&*(instruction_data.as_ptr().add(34) as *const Pubkey)), - ), - _ => return Err(ProgramError::InvalidInstructionData), + let (decimals, mint_authority, freeze_authority) = if instruction_data.len() >= 34 { + // SAFETY: The minimum size of the instruction data is either 34 or 66 bytes: + // - decimals (1 byte) + // - mint_authority (32 bytes) + // - option + freeze_authority (1 byte + 32 bytes) + unsafe { + let decimals = *instruction_data.get_unchecked(0); + let mint_authority = &*(instruction_data.as_ptr().add(1) as *const Pubkey); + let freeze_authority = if *instruction_data.get_unchecked(33) == 0 { + None + } else if *instruction_data.get_unchecked(33) == 1 && instruction_data.len() >= 66 { + Some(&*(instruction_data.as_ptr().add(34) as *const Pubkey)) + } else { + return Err(TokenError::InvalidInstruction.into()); + }; + + (decimals, mint_authority, freeze_authority) } + } else { + return Err(TokenError::InvalidInstruction.into()); }; // Validates the accounts. @@ -55,24 +56,24 @@ pub fn process_initialize_mint( (mint_info, None) }; - // SAFETY: single mutable borrow to `mint_info` account data. - let mint = unsafe { load_mut_unchecked::(mint_info.borrow_mut_data_unchecked())? }; - - if mint.is_initialized() { - return Err(TokenError::AlreadyInUse.into()); - } - - // Check rent-exempt status of the mint account. + let mint_data_len = mint_info.data_len(); let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info { // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length // are checked by `from_account_info_unchecked`. let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? }; - rent.is_exempt(mint_info.lamports(), size_of::()) + rent.is_exempt(mint_info.lamports(), mint_data_len) } else { - Rent::get()?.is_exempt(mint_info.lamports(), size_of::()) + Rent::get()?.is_exempt(mint_info.lamports(), mint_data_len) }; + // SAFETY: single mutable borrow to `mint_info` account data. + let mint = unsafe { load_mut_unchecked::(mint_info.borrow_mut_data_unchecked())? }; + + if mint.is_initialized()? { + return Err(TokenError::AlreadyInUse.into()); + } + if !is_exempt { return Err(TokenError::NotRentExempt.into()); } diff --git a/p-token/src/processor/shared/initialize_multisig.rs b/p-token/src/processor/shared/initialize_multisig.rs index 8335f04..e1285c5 100644 --- a/p-token/src/processor/shared/initialize_multisig.rs +++ b/p-token/src/processor/shared/initialize_multisig.rs @@ -46,7 +46,7 @@ pub fn process_initialize_multisig( let multisig = unsafe { load_mut_unchecked::(multisig_info.borrow_mut_data_unchecked())? }; - if multisig.is_initialized() { + if multisig.is_initialized()? { return Err(TokenError::AlreadyInUse.into()); } diff --git a/p-token/src/processor/shared/mint_to.rs b/p-token/src/processor/shared/mint_to.rs index 643da08..6850802 100644 --- a/p-token/src/processor/shared/mint_to.rs +++ b/p-token/src/processor/shared/mint_to.rs @@ -25,7 +25,7 @@ pub fn process_mint_to( let destination_account = unsafe { load_mut::(destination_account_info.borrow_mut_data_unchecked())? }; - if destination_account.is_frozen() { + if destination_account.is_frozen()? { return Err(TokenError::AccountFrozen.into()); } diff --git a/p-token/src/processor/shared/toggle_account_state.rs b/p-token/src/processor/shared/toggle_account_state.rs index cad0669..f2a2eef 100644 --- a/p-token/src/processor/shared/toggle_account_state.rs +++ b/p-token/src/processor/shared/toggle_account_state.rs @@ -18,7 +18,7 @@ pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> P let source_account = unsafe { load_mut::(source_account_info.borrow_mut_data_unchecked())? }; - if freeze == source_account.is_frozen() { + if freeze == source_account.is_frozen()? { return Err(TokenError::InvalidState.into()); } if source_account.is_native() { @@ -39,11 +39,11 @@ pub fn process_toggle_account_state(accounts: &[AccountInfo], freeze: bool) -> P None => Err(TokenError::MintCannotFreeze.into()), }?; - source_account.state = if freeze { + source_account.set_account_state(if freeze { AccountState::Frozen } else { AccountState::Initialized - }; + }); Ok(()) } diff --git a/p-token/src/processor/shared/transfer.rs b/p-token/src/processor/shared/transfer.rs index 80aaac5..269ab60 100644 --- a/p-token/src/processor/shared/transfer.rs +++ b/p-token/src/processor/shared/transfer.rs @@ -77,7 +77,7 @@ pub fn process_transfer( // destination accounts are not frozen, have the same mint, and the source // account has enough tokens. let remaining_amount = if self_transfer { - if source_account.is_frozen() { + if source_account.is_frozen()? { return Err(TokenError::AccountFrozen.into()); } @@ -92,7 +92,7 @@ pub fn process_transfer( let destination_account = unsafe { load::(destination_account_info.borrow_data_unchecked())? }; - if source_account.is_frozen() || destination_account.is_frozen() { + if source_account.is_frozen()? || destination_account.is_frozen()? { return Err(TokenError::AccountFrozen.into()); } diff --git a/p-token/src/processor/transfer.rs b/p-token/src/processor/transfer.rs index eadb03d..2d75354 100644 --- a/p-token/src/processor/transfer.rs +++ b/p-token/src/processor/transfer.rs @@ -1,15 +1,11 @@ use { - super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + super::{shared, unpack_amount}, + pinocchio::{account_info::AccountInfo, ProgramResult}, }; #[inline(always)] pub fn process_transfer(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult { - let amount = u64::from_le_bytes( - instruction_data - .try_into() - .map_err(|_error| ProgramError::InvalidInstructionData)?, - ); + let amount = unpack_amount(instruction_data)?; shared::transfer::process_transfer(accounts, amount, None) } diff --git a/p-token/src/processor/transfer_checked.rs b/p-token/src/processor/transfer_checked.rs index 16f742d..9a1a895 100644 --- a/p-token/src/processor/transfer_checked.rs +++ b/p-token/src/processor/transfer_checked.rs @@ -1,6 +1,6 @@ use { - super::shared, - pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult}, + super::{shared, unpack_amount_and_decimals}, + pinocchio::{account_info::AccountInfo, ProgramResult}, }; #[inline(always)] @@ -8,16 +8,7 @@ pub fn process_transfer_checked( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - // expected u64 (8) + u8 (1) - let (amount, decimals) = if instruction_data.len() == 9 { - let (amount, decimals) = instruction_data.split_at(core::mem::size_of::()); - ( - u64::from_le_bytes(amount.try_into().unwrap()), - decimals.first().copied(), - ) - } else { - return Err(ProgramError::InvalidInstructionData); - }; + let (amount, decimals) = unpack_amount_and_decimals(instruction_data)?; - shared::transfer::process_transfer(accounts, amount, decimals) + shared::transfer::process_transfer(accounts, amount, Some(decimals)) } diff --git a/p-token/src/processor/ui_amount_to_amount.rs b/p-token/src/processor/ui_amount_to_amount.rs index b479d1b..cadcf62 100644 --- a/p-token/src/processor/ui_amount_to_amount.rs +++ b/p-token/src/processor/ui_amount_to_amount.rs @@ -15,8 +15,7 @@ pub fn process_ui_amount_to_amount( accounts: &[AccountInfo], instruction_data: &[u8], ) -> ProgramResult { - let ui_amount = - from_utf8(instruction_data).map_err(|_error| ProgramError::InvalidInstructionData)?; + let ui_amount = from_utf8(instruction_data).map_err(|_error| TokenError::InvalidInstruction)?; let mint_info = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?; check_account_owner(mint_info)?; From 8921377ea5cd109d49a888b8ef57f041d6f20ce1 Mon Sep 17 00:00:00 2001 From: Jon C Date: Tue, 3 Jun 2025 12:07:02 +0200 Subject: [PATCH 335/335] Create SECURITY.md --- SECURITY.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..39b428a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,39 @@ +# Security Policy + +## Reporting security problems + +**DO NOT CREATE A GITHUB ISSUE** to report a security problem. + +Instead please use this [Report a Vulnerability](https://github.com/solana-program/token/security/advisories/new) link. +Provide a helpful title and detailed description of the problem. + +If you haven't done so already, please **enable two-factor auth** in your GitHub account. + +Expect a response as fast as possible in the advisory, typically within 72 hours. + +-- + +If you do not receive a response in the advisory, send an email to + with the full URL of the advisory you have created. DO NOT +include attachments or provide detail sufficient for exploitation regarding the +security issue in this email. **Only provide such details in the advisory**. + +If you do not receive a response from please followup with +the team directly. You can do this in one of the `#Dev Tooling` channels of the +[Solana Tech discord server](https://solana.com/discord), by pinging the admins +in the channel and referencing the fact that you submitted a security problem. + +## Security Bug Bounties + +The Solana Foundation offer bounties for critical security issues. Please +see the [Agave Security Bug +Bounties](https://github.com/anza-xyz/agave/security/policy#security-bug-bounties) +for details on classes of bugs and payment amounts. + +## Scope + +Only the `spl-token` program is included in the bounty scope, at +[program](https://github.com/solana-program/token/tree/master/program). + +If you discover a critical security issue in an out-of-scope component, your finding +may still be valuable.