diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml index b3952d8cb9..02d62b02d7 100644 --- a/.github/workflows/js.yml +++ b/.github/workflows/js.yml @@ -2,17 +2,9 @@ on: push: branches: - main - paths: - - "js/stateless.js/**" - - "js/compressed-token/**" - - ".github/workflows/js.yml" pull_request: branches: - main - paths: - - "js/stateless.js/**" - - "js/compressed-token/**" - - ".github/workflows/js.yml" types: - opened - synchronize @@ -34,7 +26,6 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 - with: - name: Setup and build uses: ./.github/actions/setup-and-build diff --git a/js/compressed-token/src/idl/psp_compressed_token.ts b/js/compressed-token/src/idl/psp_compressed_token.ts index 57eeccfa7c..348a55bfb5 100644 --- a/js/compressed-token/src/idl/psp_compressed_token.ts +++ b/js/compressed-token/src/idl/psp_compressed_token.ts @@ -332,7 +332,7 @@ export type PspCompressedToken = { type: 'bool'; }, { - name: 'deCompressAmount'; + name: 'deCompressLamports'; type: { option: 'u64'; }; @@ -422,6 +422,16 @@ export type PspCompressedToken = { option: 'u64'; }; }, + { + name: 'deCompressLamports'; + type: { + option: 'u64'; + }; + }, + { + name: 'isCompress'; + type: 'bool'; + }, ]; }; }, @@ -1035,7 +1045,7 @@ export const IDL: PspCompressedToken = { type: 'bool', }, { - name: 'deCompressAmount', + name: 'deCompressLamports', type: { option: 'u64', }, @@ -1125,6 +1135,16 @@ export const IDL: PspCompressedToken = { option: 'u64', }, }, + { + name: 'deCompressLamports', + type: { + option: 'u64', + }, + }, + { + name: 'isCompress', + type: 'bool', + }, ], }, }, diff --git a/js/stateless.js/package.json b/js/stateless.js/package.json index d8c68ca704..038f5f23af 100644 --- a/js/stateless.js/package.json +++ b/js/stateless.js/package.json @@ -23,8 +23,10 @@ "test-all": "vitest run", "test:unit:all": "EXCLUDE_E2E=true vitest run", "test-validator": "./../../cli/test_bin/run test-validator", - "pretest:e2e": "./../../cli/test_bin/run test-validator -b ", + "gnark-prover": "../../circuit-lib/circuit-lib.js/scripts/prover.sh", + "pretest:e2e": "./../../cli/test_bin/run test-validator -b && pnpm gnark-prover", "test:e2e:transfer": "pnpm pretest:e2e && vitest run tests/e2e/transfer.test.ts", + "test:e2e:compress": "pnpm pretest:e2e && vitest run tests/e2e/compress.test.ts", "test:e2e:all": "pnpm pretest:e2e && vitest run tests/e2e/*.test.ts", "test:index": "vitest run tests/e2e/program.test.ts", "test:e2e:serde": "vitest run tests/e2e/serde.test.ts", diff --git a/js/stateless.js/src/idls/index.ts b/js/stateless.js/src/idls/index.ts index 2c583657ac..d0b9fdcfa3 100644 --- a/js/stateless.js/src/idls/index.ts +++ b/js/stateless.js/src/idls/index.ts @@ -3,10 +3,7 @@ import { IDL as AccountCompressionIDL, AccountCompression, } from './account_compression'; -import { - IDL as LightMerkleTreeProgramIDL, - LightMerkleTreeProgram, -} from './light_merkle_tree_program'; + import { IDL as LightIDL, Light } from './light'; import { IDL as PspCompressedPdaIDL, @@ -17,8 +14,6 @@ import { IDL as UserRegistryIDL, UserRegistry } from './user_registry'; export { AccountCompressionIDL, AccountCompression, - LightMerkleTreeProgramIDL, - LightMerkleTreeProgram, LightIDL, Light, PspCompressedPdaIDL, diff --git a/js/stateless.js/src/idls/light_merkle_tree_program.ts b/js/stateless.js/src/idls/light_merkle_tree_program.ts deleted file mode 100644 index 316afca691..0000000000 --- a/js/stateless.js/src/idls/light_merkle_tree_program.ts +++ /dev/null @@ -1,1747 +0,0 @@ -export type LightMerkleTreeProgram = { - version: '0.3.1'; - name: 'light_merkle_tree_program'; - constants: [ - { - name: 'ENCRYPTED_UTXOS_LENGTH'; - type: { - defined: 'usize'; - }; - value: '174'; - }, - { - name: 'MERKLE_TREE_HEIGHT'; - type: { - defined: 'usize'; - }; - value: '22'; - }, - { - name: 'MERKLE_TREE_CHANGELOG'; - type: { - defined: 'usize'; - }; - value: '0'; - }, - { - name: 'MERKLE_TREE_ROOTS'; - type: { - defined: 'usize'; - }; - value: '2800'; - }, - { - name: 'INITIAL_MERKLE_TREE_AUTHORITY'; - type: { - array: ['u8', 32]; - }; - value: '[2 , 99 , 226 , 251 , 88 , 66 , 92 , 33 , 25 , 216 , 211 , 185 , 112 , 203 , 212 , 238 , 105 , 144 , 72 , 121 , 176 , 253 , 106 , 168 , 115 , 158 , 154 , 188 , 62 , 255 , 166 , 81 ,]'; - }, - { - name: 'ZERO_BYTES_MERKLE_TREE_18'; - type: { - array: [ - { - array: ['u8', 32]; - }, - 19, - ]; - }; - value: '[[40 , 66 , 58 , 227 , 48 , 224 , 249 , 227 , 188 , 18 , 133 , 168 , 156 , 214 , 220 , 144 , 244 , 144 , 67 , 82 , 76 , 6 , 135 , 78 , 64 , 186 , 52 , 113 , 234 , 47 , 27 , 32 ,] , [227 , 42 , 164 , 149 , 188 , 70 , 170 , 8 , 197 , 44 , 134 , 162 , 211 , 186 , 50 , 238 , 97 , 71 , 25 , 130 , 77 , 70 , 37 , 128 , 172 , 154 , 54 , 111 , 93 , 193 , 105 , 27 ,] , [25 , 241 , 255 , 33 , 65 , 214 , 48 , 229 , 38 , 116 , 134 , 103 , 44 , 146 , 163 , 214 , 31 , 238 , 148 , 206 , 34 , 137 , 144 , 221 , 184 , 11 , 5 , 213 , 10 , 188 , 143 , 18 ,] , [211 , 61 , 251 , 33 , 128 , 34 , 4 , 100 , 229 , 47 , 99 , 121 , 109 , 204 , 224 , 90 , 200 , 149 , 219 , 20 , 48 , 206 , 210 , 177 , 161 , 66 , 44 , 10 , 169 , 56 , 248 , 8 ,] , [200 , 15 , 65 , 80 , 151 , 74 , 72 , 69 , 229 , 131 , 25 , 215 , 86 , 36 , 195 , 74 , 67 , 59 , 117 , 179 , 51 , 60 , 181 , 13 , 242 , 192 , 228 , 228 , 189 , 238 , 70 , 8 ,] , [171 , 62 , 122 , 81 , 181 , 197 , 22 , 238 , 224 , 40 , 154 , 231 , 127 , 202 , 201 , 169 , 196 , 109 , 244 , 175 , 117 , 101 , 23 , 67 , 103 , 57 , 127 , 200 , 37 , 43 , 111 , 7 ,] , [59 , 78 , 126 , 104 , 199 , 143 , 213 , 10 , 2 , 158 , 64 , 78 , 153 , 25 , 107 , 190 , 32 , 122 , 123 , 211 , 116 , 179 , 175 , 172 , 70 , 54 , 175 , 59 , 201 , 120 , 64 , 44 ,] , [110 , 91 , 92 , 81 , 205 , 89 , 122 , 223 , 55 , 163 , 42 , 227 , 109 , 54 , 38 , 22 , 110 , 217 , 29 , 148 , 107 , 99 , 128 , 106 , 146 , 47 , 239 , 41 , 55 , 157 , 155 , 22 ,] , [18 , 231 , 42 , 5 , 245 , 159 , 211 , 227 , 239 , 89 , 35 , 142 , 223 , 69 , 166 , 224 , 14 , 114 , 128 , 14 , 123 , 123 , 215 , 2 , 241 , 185 , 191 , 60 , 252 , 61 , 146 , 12 ,] , [231 , 0 , 84 , 227 , 127 , 64 , 158 , 7 , 171 , 179 , 137 , 231 , 92 , 87 , 25 , 221 , 156 , 229 , 53 , 208 , 194 , 201 , 12 , 165 , 105 , 150 , 41 , 142 , 29 , 205 , 136 , 29 ,] , [195 , 2 , 103 , 231 , 62 , 207 , 214 , 105 , 214 , 210 , 108 , 23 , 28 , 151 , 77 , 100 , 78 , 194 , 210 , 29 , 227 , 14 , 17 , 242 , 211 , 50 , 33 , 194 , 106 , 18 , 246 , 45 ,] , [131 , 178 , 24 , 157 , 251 , 247 , 103 , 69 , 101 , 229 , 194 , 14 , 167 , 57 , 158 , 128 , 212 , 19 , 140 , 234 , 69 , 37 , 10 , 156 , 249 , 96 , 152 , 52 , 97 , 96 , 119 , 41 ,] , [30 , 223 , 20 , 181 , 108 , 110 , 112 , 102 , 234 , 54 , 99 , 29 , 213 , 3 , 55 , 225 , 125 , 185 , 223 , 234 , 188 , 108 , 83 , 89 , 27 , 3 , 100 , 6 , 65 , 107 , 3 , 24 ,] , [167 , 32 , 85 , 233 , 205 , 253 , 154 , 214 , 236 , 82 , 147 , 75 , 252 , 144 , 109 , 73 , 63 , 167 , 77 , 233 , 12 , 201 , 150 , 242 , 103 , 15 , 158 , 83 , 137 , 24 , 170 , 16 ,] , [45 , 98 , 238 , 69 , 136 , 141 , 101 , 226 , 94 , 209 , 58 , 215 , 212 , 14 , 210 , 135 , 110 , 96 , 52 , 16 , 101 , 177 , 121 , 109 , 134 , 81 , 189 , 146 , 113 , 243 , 97 , 42 ,] , [71 , 51 , 251 , 48 , 95 , 193 , 94 , 26 , 180 , 17 , 124 , 203 , 48 , 98 , 55 , 17 , 60 , 104 , 186 , 175 , 213 , 189 , 7 , 239 , 92 , 175 , 16 , 5 , 220 , 168 , 70 , 21 ,] , [35 , 92 , 72 , 197 , 23 , 142 , 16 , 200 , 136 , 38 , 44 , 255 , 162 , 115 , 11 , 1 , 248 , 182 , 236 , 78 , 90 , 24 , 128 , 245 , 168 , 17 , 130 , 2 , 73 , 51 , 196 , 6 ,] , [89 , 178 , 154 , 246 , 236 , 130 , 30 , 100 , 27 , 230 , 24 , 196 , 8 , 172 , 176 , 196 , 197 , 13 , 157 , 194 , 169 , 106 , 207 , 70 , 66 , 117 , 69 , 53 , 56 , 154 , 78 , 0 ,] , [231 , 174 , 226 , 37 , 211 , 160 , 187 , 178 , 149 , 82 , 17 , 60 , 110 , 116 , 28 , 61 , 58 , 145 , 58 , 71 , 25 , 42 , 67 , 46 , 189 , 214 , 248 , 234 , 182 , 251 , 238 , 34 ,] ,]'; - }, - { - name: 'IX_ORDER'; - type: { - array: ['u8', 57]; - }; - value: '[34 , 14 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 241 ,]'; - }, - { - name: 'AUTHORITY_SEED'; - type: 'bytes'; - value: '[65, 85, 84, 72, 79, 82, 73, 84, 89, 95, 83, 69, 69, 68]'; - }, - { - name: 'MERKLE_TREE_AUTHORITY_SEED'; - type: 'bytes'; - value: '[77, 69, 82, 75, 76, 69, 95, 84, 82, 69, 69, 95, 65, 85, 84, 72, 79, 82, 73, 84, 89]'; - }, - { - name: 'TREE_ROOT_SEED'; - type: 'bytes'; - value: '[84, 82, 69, 69, 95, 82, 79, 79, 84, 95, 83, 69, 69, 68]'; - }, - { - name: 'STORAGE_SEED'; - type: 'bytes'; - value: '[115, 116, 111, 114, 97, 103, 101]'; - }, - { - name: 'LEAVES_SEED'; - type: 'bytes'; - value: '[108, 101, 97, 118, 101, 115]'; - }, - { - name: 'NULLIFIER_SEED'; - type: 'bytes'; - value: '[110, 102]'; - }, - { - name: 'POOL_TYPE_SEED'; - type: 'bytes'; - value: '[112, 111, 111, 108, 116, 121, 112, 101]'; - }, - { - name: 'POOL_CONFIG_SEED'; - type: 'bytes'; - value: '[112, 111, 111, 108, 45, 99, 111, 110, 102, 105, 103]'; - }, - { - name: 'POOL_SEED'; - type: 'bytes'; - value: '[112, 111, 111, 108]'; - }, - { - name: 'TOKEN_AUTHORITY_SEED'; - type: 'bytes'; - value: '[115, 112, 108]'; - }, - ]; - instructions: [ - { - name: 'initializeNewMerkleTreeSet'; - docs: [ - 'Initializes a new Merkle tree from config bytes.', - 'Can only be called from the merkle_tree_authority.', - ]; - accounts: [ - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'newMerkleTreeSet'; - isMut: true; - isSigner: false; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'rent'; - isMut: false; - isSigner: false; - }, - { - name: 'merkleTreeAuthorityPda'; - isMut: true; - isSigner: false; - }, - ]; - args: []; - }, - { - name: 'initializeMerkleTreeAuthority'; - docs: [ - 'Initializes a new merkle tree authority which can register new verifiers and configure', - 'permissions to create new pools.', - ]; - accounts: [ - { - name: 'merkleTreeAuthorityPda'; - isMut: true; - isSigner: false; - }, - { - name: 'merkleTreeSet'; - isMut: true; - isSigner: false; - }, - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'rent'; - isMut: false; - isSigner: false; - }, - ]; - args: []; - }, - { - name: 'updateMerkleTreeAuthority'; - docs: ['Updates the merkle tree authority to a new authority.']; - accounts: [ - { - name: 'merkleTreeAuthorityPda'; - isMut: true; - isSigner: false; - }, - { - name: 'authority'; - isMut: false; - isSigner: true; - }, - { - name: 'newAuthority'; - isMut: false; - isSigner: false; - }, - ]; - args: []; - }, - { - name: 'enablePermissionlessSplTokens'; - docs: ['Enables anyone to create token pools.']; - accounts: [ - { - name: 'merkleTreeAuthorityPda'; - isMut: true; - isSigner: false; - }, - { - name: 'authority'; - isMut: false; - isSigner: true; - }, - ]; - args: [ - { - name: 'enablePermissionless'; - type: 'bool'; - }, - ]; - }, - { - name: 'registerVerifier'; - docs: [ - 'Registers a new verifier which can decompress tokens, insert new nullifiers, add new leaves.', - 'These functions can only be invoked from registered verifiers.', - ]; - accounts: [ - { - name: 'registeredVerifierPda'; - isMut: true; - isSigner: false; - }, - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'merkleTreeAuthorityPda'; - isMut: false; - isSigner: false; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'rent'; - isMut: false; - isSigner: false; - }, - ]; - args: [ - { - name: 'verifierPubkey'; - type: 'publicKey'; - }, - ]; - }, - { - name: 'registerPoolType'; - docs: ['Registers a new pooltype.']; - accounts: [ - { - name: 'registeredPoolTypePda'; - isMut: true; - isSigner: false; - }, - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'rent'; - isMut: false; - isSigner: false; - }, - { - name: 'merkleTreeAuthorityPda'; - isMut: false; - isSigner: false; - }, - ]; - args: [ - { - name: 'poolType'; - type: { - array: ['u8', 32]; - }; - }, - ]; - }, - { - name: 'registerSplPool'; - docs: [ - 'Creates a new spl token pool which can be used by any registered verifier.', - ]; - accounts: [ - { - name: 'registeredAssetPoolPda'; - isMut: true; - isSigner: false; - }, - { - name: 'merkleTreePdaToken'; - isMut: true; - isSigner: false; - }, - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'rent'; - isMut: false; - isSigner: false; - }, - { - name: 'mint'; - isMut: true; - isSigner: false; - }, - { - name: 'tokenAuthority'; - isMut: true; - isSigner: false; - }, - { - name: 'tokenProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'registeredPoolTypePda'; - isMut: false; - isSigner: false; - docs: ['Just needs to exist and be derived correctly.']; - }, - { - name: 'merkleTreeAuthorityPda'; - isMut: true; - isSigner: false; - }, - ]; - args: []; - }, - { - name: 'registerSolPool'; - docs: [ - 'Creates a new sol pool which can be used by any registered verifier.', - ]; - accounts: [ - { - name: 'registeredAssetPoolPda'; - isMut: true; - isSigner: false; - }, - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'rent'; - isMut: false; - isSigner: false; - }, - { - name: 'registeredPoolTypePda'; - isMut: false; - isSigner: false; - }, - { - name: 'merkleTreeAuthorityPda'; - isMut: true; - isSigner: false; - }, - ]; - args: []; - }, - { - name: 'insertTwoLeaves'; - docs: [ - 'Creates and initializes a pda which stores two merkle tree leaves and encrypted Utxos.', - 'The inserted leaves are not part of the Merkle tree yet and marked accordingly.', - 'The Merkle tree has to be updated after.', - 'Can only be called from a registered verifier program.', - ]; - accounts: [ - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'merkleTreeSet'; - isMut: true; - isSigner: false; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'registeredVerifierPda'; - isMut: false; - isSigner: false; - }, - { - name: 'logWrapper'; - isMut: false; - isSigner: false; - }, - ]; - args: [ - { - name: 'leaves'; - type: { - vec: { - array: ['u8', 32]; - }; - }; - }, - ]; - }, - { - name: 'insertTwoLeavesEvent'; - accounts: [ - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'merkleTreeSet'; - isMut: true; - isSigner: false; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'registeredVerifier'; - isMut: false; - isSigner: false; - }, - ]; - args: [ - { - name: 'leafLeft'; - type: { - array: ['u8', 32]; - }; - }, - { - name: 'leafRight'; - type: { - array: ['u8', 32]; - }; - }, - ]; - }, - { - name: 'decompressSol'; - docs: [ - 'Decompresses sol from a liquidity pool.', - 'An arbitrary number of recipients can be passed in with remaining accounts.', - 'Can only be called from a registered verifier program.', - ]; - accounts: [ - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'merkleTreeToken'; - isMut: true; - isSigner: false; - }, - { - name: 'registeredVerifierPda'; - isMut: true; - isSigner: false; - }, - { - name: 'recipient'; - isMut: true; - isSigner: false; - }, - ]; - args: [ - { - name: 'amount'; - type: 'u64'; - }, - ]; - }, - { - name: 'decompressSpl'; - docs: [ - 'Decompresses spl tokens from a liquidity pool.', - 'An arbitrary number of recipients can be passed in with remaining accounts.', - 'Can only be called from a registered verifier program.', - ]; - accounts: [ - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'merkleTreeToken'; - isMut: true; - isSigner: false; - }, - { - name: 'recipient'; - isMut: true; - isSigner: false; - }, - { - name: 'tokenProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'tokenAuthority'; - isMut: true; - isSigner: false; - }, - { - name: 'registeredVerifierPda'; - isMut: false; - isSigner: false; - }, - ]; - args: [ - { - name: 'amount'; - type: 'u64'; - }, - ]; - }, - { - name: 'initializeNullifiers'; - accounts: [ - { - name: 'authority'; - isMut: true; - isSigner: true; - }, - { - name: 'systemProgram'; - isMut: false; - isSigner: false; - }, - { - name: 'registeredVerifierPda'; - isMut: false; - isSigner: false; - }, - ]; - args: [ - { - name: 'nullifiers'; - type: { - vec: { - array: ['u8', 32]; - }; - }; - }, - ]; - }, - ]; - accounts: [ - { - name: 'registeredAssetPool'; - docs: [ - 'Nullfier pdas are derived from the nullifier', - 'existence of a nullifier is the check to prevent double spends.', - ]; - type: { - kind: 'struct'; - fields: [ - { - name: 'assetPoolPubkey'; - type: 'publicKey'; - }, - { - name: 'poolType'; - type: { - array: ['u8', 32]; - }; - }, - { - name: 'index'; - type: 'u64'; - }, - ]; - }; - }, - { - name: 'registeredPoolType'; - docs: ['Pool type']; - type: { - kind: 'struct'; - fields: [ - { - name: 'poolType'; - type: { - array: ['u8', 32]; - }; - }, - ]; - }; - }, - { - name: 'merkleTreeAuthority'; - docs: [ - 'Configures the authority of the merkle tree which can:', - '- register new verifiers', - '- register new asset pools', - '- register new asset pool types', - '- set permissions for new asset pool creation', - '- keeps current highest index for assets and merkle trees to enable lookups of these', - ]; - type: { - kind: 'struct'; - fields: [ - { - name: 'pubkey'; - type: 'publicKey'; - }, - { - name: 'merkleTreeSetIndex'; - type: 'u64'; - }, - { - name: 'registeredAssetIndex'; - type: 'u64'; - }, - { - name: 'enablePermissionlessSplTokens'; - type: 'bool'; - }, - { - name: 'enablePermissionlessMerkleTreeRegistration'; - type: 'bool'; - }, - ]; - }; - }, - { - name: 'registeredVerifier'; - docs: ['']; - type: { - kind: 'struct'; - fields: [ - { - name: 'pubkey'; - type: 'publicKey'; - }, - ]; - }; - }, - { - name: 'merkleTreeSet'; - docs: ['Set of on-chain Merkle trees.']; - type: { - kind: 'struct'; - fields: [ - { - name: 'index'; - docs: ['Unique index.']; - type: 'u64'; - }, - { - name: 'nextMerkleTree'; - docs: ['Public key of the next Merkle tree set.']; - type: 'publicKey'; - }, - { - name: 'owner'; - docs: ['Owner of the Merkle tree set.']; - type: 'publicKey'; - }, - { - name: 'stateMerkleTree'; - docs: ['Merkle tree for the transaction state.']; - type: { - array: ['u8', 90368]; - }; - }, - { - name: 'eventMerkleTree'; - docs: ['Merkle tree for event compression.']; - type: { - array: ['u8', 90368]; - }; - }, - ]; - }; - }, - ]; - errors: [ - { - code: 6000; - name: 'MtTmpPdaInitFailed'; - msg: 'Merkle tree tmp account init failed wrong pda.'; - }, - { - code: 6001; - name: 'MerkleTreeInitFailed'; - msg: 'Merkle tree tmp account init failed.'; - }, - { - code: 6002; - name: 'ContractStillLocked'; - msg: 'Contract is still locked.'; - }, - { - code: 6003; - name: 'InvalidMerkleTree'; - msg: 'InvalidMerkleTree.'; - }, - { - code: 6004; - name: 'InvalidMerkleTreeOwner'; - msg: 'InvalidMerkleTreeOwner.'; - }, - { - code: 6005; - name: 'PubkeyCheckFailed'; - msg: 'PubkeyCheckFailed'; - }, - { - code: 6006; - name: 'CloseAccountFailed'; - msg: 'CloseAccountFailed'; - }, - { - code: 6007; - name: 'DecompressFailed'; - msg: 'DecompressFailed'; - }, - { - code: 6008; - name: 'MerkleTreeUpdateNotInRootInsert'; - msg: 'MerkleTreeUpdateNotInRootInsert'; - }, - { - code: 6009; - name: 'MerkleTreeUpdateNotInRootInsertState'; - msg: 'MerkleTreeUpdateNotInRootInsert'; - }, - { - code: 6010; - name: 'InvalidNumberOfLeaves'; - msg: 'InvalidNumberOfLeaves'; - }, - { - code: 6011; - name: 'LeafAlreadyInserted'; - msg: 'LeafAlreadyInserted'; - }, - { - code: 6012; - name: 'WrongLeavesLastTx'; - msg: 'WrongLeavesLastTx'; - }, - { - code: 6013; - name: 'FirstLeavesPdaIncorrectIndex'; - msg: 'FirstLeavesPdaIncorrectIndex'; - }, - { - code: 6014; - name: 'NullifierAlreadyExists'; - msg: 'NullifierAlreadyExists'; - }, - { - code: 6015; - name: 'LeavesOfWrongTree'; - msg: 'LeavesOfWrongTree'; - }, - { - code: 6016; - name: 'InvalidAuthority'; - msg: 'InvalidAuthority'; - }, - { - code: 6017; - name: 'InvalidVerifier'; - msg: 'InvalidVerifier'; - }, - { - code: 6018; - name: 'PubkeyTryFromFailed'; - msg: 'PubkeyTryFromFailed'; - }, - { - code: 6019; - name: 'ExpectedOldMerkleTrees'; - msg: 'Expected old Merkle trees as remaining account.'; - }, - { - code: 6020; - name: 'InvalidOldMerkleTree'; - msg: 'Invalid old Merkle tree account.'; - }, - { - code: 6021; - name: 'NotNewestOldMerkleTree'; - msg: 'Provided old Merkle tree is not the newest one.'; - }, - { - code: 6022; - name: 'ExpectedTwoLeavesPda'; - msg: 'Expected two leaves PDA as a remaining account.'; - }, - { - code: 6023; - name: 'InvalidTwoLeavesPda'; - msg: 'Invalid two leaves PDA.'; - }, - { - code: 6024; - name: 'OddNumberOfLeaves'; - msg: 'Odd number of leaves.'; - }, - { - code: 6025; - name: 'IntegerOverflow'; - msg: 'Integer overflow, value too large'; - }, - { - code: 6026; - name: 'InvalidNoopPubkey'; - msg: 'Provided noop program public key is invalid'; - }, - { - code: 6027; - name: 'EventNoChangelogEntry'; - msg: 'Emitting an event requires at least one changelog entry'; - }, - ]; -}; - -export const IDL: LightMerkleTreeProgram = { - version: '0.3.1', - name: 'light_merkle_tree_program', - constants: [ - { - name: 'ENCRYPTED_UTXOS_LENGTH', - type: { - defined: 'usize', - }, - value: '174', - }, - { - name: 'MERKLE_TREE_HEIGHT', - type: { - defined: 'usize', - }, - value: '22', - }, - { - name: 'MERKLE_TREE_CHANGELOG', - type: { - defined: 'usize', - }, - value: '0', - }, - { - name: 'MERKLE_TREE_ROOTS', - type: { - defined: 'usize', - }, - value: '2800', - }, - { - name: 'INITIAL_MERKLE_TREE_AUTHORITY', - type: { - array: ['u8', 32], - }, - value: '[2 , 99 , 226 , 251 , 88 , 66 , 92 , 33 , 25 , 216 , 211 , 185 , 112 , 203 , 212 , 238 , 105 , 144 , 72 , 121 , 176 , 253 , 106 , 168 , 115 , 158 , 154 , 188 , 62 , 255 , 166 , 81 ,]', - }, - { - name: 'ZERO_BYTES_MERKLE_TREE_18', - type: { - array: [ - { - array: ['u8', 32], - }, - 19, - ], - }, - value: '[[40 , 66 , 58 , 227 , 48 , 224 , 249 , 227 , 188 , 18 , 133 , 168 , 156 , 214 , 220 , 144 , 244 , 144 , 67 , 82 , 76 , 6 , 135 , 78 , 64 , 186 , 52 , 113 , 234 , 47 , 27 , 32 ,] , [227 , 42 , 164 , 149 , 188 , 70 , 170 , 8 , 197 , 44 , 134 , 162 , 211 , 186 , 50 , 238 , 97 , 71 , 25 , 130 , 77 , 70 , 37 , 128 , 172 , 154 , 54 , 111 , 93 , 193 , 105 , 27 ,] , [25 , 241 , 255 , 33 , 65 , 214 , 48 , 229 , 38 , 116 , 134 , 103 , 44 , 146 , 163 , 214 , 31 , 238 , 148 , 206 , 34 , 137 , 144 , 221 , 184 , 11 , 5 , 213 , 10 , 188 , 143 , 18 ,] , [211 , 61 , 251 , 33 , 128 , 34 , 4 , 100 , 229 , 47 , 99 , 121 , 109 , 204 , 224 , 90 , 200 , 149 , 219 , 20 , 48 , 206 , 210 , 177 , 161 , 66 , 44 , 10 , 169 , 56 , 248 , 8 ,] , [200 , 15 , 65 , 80 , 151 , 74 , 72 , 69 , 229 , 131 , 25 , 215 , 86 , 36 , 195 , 74 , 67 , 59 , 117 , 179 , 51 , 60 , 181 , 13 , 242 , 192 , 228 , 228 , 189 , 238 , 70 , 8 ,] , [171 , 62 , 122 , 81 , 181 , 197 , 22 , 238 , 224 , 40 , 154 , 231 , 127 , 202 , 201 , 169 , 196 , 109 , 244 , 175 , 117 , 101 , 23 , 67 , 103 , 57 , 127 , 200 , 37 , 43 , 111 , 7 ,] , [59 , 78 , 126 , 104 , 199 , 143 , 213 , 10 , 2 , 158 , 64 , 78 , 153 , 25 , 107 , 190 , 32 , 122 , 123 , 211 , 116 , 179 , 175 , 172 , 70 , 54 , 175 , 59 , 201 , 120 , 64 , 44 ,] , [110 , 91 , 92 , 81 , 205 , 89 , 122 , 223 , 55 , 163 , 42 , 227 , 109 , 54 , 38 , 22 , 110 , 217 , 29 , 148 , 107 , 99 , 128 , 106 , 146 , 47 , 239 , 41 , 55 , 157 , 155 , 22 ,] , [18 , 231 , 42 , 5 , 245 , 159 , 211 , 227 , 239 , 89 , 35 , 142 , 223 , 69 , 166 , 224 , 14 , 114 , 128 , 14 , 123 , 123 , 215 , 2 , 241 , 185 , 191 , 60 , 252 , 61 , 146 , 12 ,] , [231 , 0 , 84 , 227 , 127 , 64 , 158 , 7 , 171 , 179 , 137 , 231 , 92 , 87 , 25 , 221 , 156 , 229 , 53 , 208 , 194 , 201 , 12 , 165 , 105 , 150 , 41 , 142 , 29 , 205 , 136 , 29 ,] , [195 , 2 , 103 , 231 , 62 , 207 , 214 , 105 , 214 , 210 , 108 , 23 , 28 , 151 , 77 , 100 , 78 , 194 , 210 , 29 , 227 , 14 , 17 , 242 , 211 , 50 , 33 , 194 , 106 , 18 , 246 , 45 ,] , [131 , 178 , 24 , 157 , 251 , 247 , 103 , 69 , 101 , 229 , 194 , 14 , 167 , 57 , 158 , 128 , 212 , 19 , 140 , 234 , 69 , 37 , 10 , 156 , 249 , 96 , 152 , 52 , 97 , 96 , 119 , 41 ,] , [30 , 223 , 20 , 181 , 108 , 110 , 112 , 102 , 234 , 54 , 99 , 29 , 213 , 3 , 55 , 225 , 125 , 185 , 223 , 234 , 188 , 108 , 83 , 89 , 27 , 3 , 100 , 6 , 65 , 107 , 3 , 24 ,] , [167 , 32 , 85 , 233 , 205 , 253 , 154 , 214 , 236 , 82 , 147 , 75 , 252 , 144 , 109 , 73 , 63 , 167 , 77 , 233 , 12 , 201 , 150 , 242 , 103 , 15 , 158 , 83 , 137 , 24 , 170 , 16 ,] , [45 , 98 , 238 , 69 , 136 , 141 , 101 , 226 , 94 , 209 , 58 , 215 , 212 , 14 , 210 , 135 , 110 , 96 , 52 , 16 , 101 , 177 , 121 , 109 , 134 , 81 , 189 , 146 , 113 , 243 , 97 , 42 ,] , [71 , 51 , 251 , 48 , 95 , 193 , 94 , 26 , 180 , 17 , 124 , 203 , 48 , 98 , 55 , 17 , 60 , 104 , 186 , 175 , 213 , 189 , 7 , 239 , 92 , 175 , 16 , 5 , 220 , 168 , 70 , 21 ,] , [35 , 92 , 72 , 197 , 23 , 142 , 16 , 200 , 136 , 38 , 44 , 255 , 162 , 115 , 11 , 1 , 248 , 182 , 236 , 78 , 90 , 24 , 128 , 245 , 168 , 17 , 130 , 2 , 73 , 51 , 196 , 6 ,] , [89 , 178 , 154 , 246 , 236 , 130 , 30 , 100 , 27 , 230 , 24 , 196 , 8 , 172 , 176 , 196 , 197 , 13 , 157 , 194 , 169 , 106 , 207 , 70 , 66 , 117 , 69 , 53 , 56 , 154 , 78 , 0 ,] , [231 , 174 , 226 , 37 , 211 , 160 , 187 , 178 , 149 , 82 , 17 , 60 , 110 , 116 , 28 , 61 , 58 , 145 , 58 , 71 , 25 , 42 , 67 , 46 , 189 , 214 , 248 , 234 , 182 , 251 , 238 , 34 ,] ,]', - }, - { - name: 'IX_ORDER', - type: { - array: ['u8', 57], - }, - value: '[34 , 14 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , 241 ,]', - }, - { - name: 'AUTHORITY_SEED', - type: 'bytes', - value: '[65, 85, 84, 72, 79, 82, 73, 84, 89, 95, 83, 69, 69, 68]', - }, - { - name: 'MERKLE_TREE_AUTHORITY_SEED', - type: 'bytes', - value: '[77, 69, 82, 75, 76, 69, 95, 84, 82, 69, 69, 95, 65, 85, 84, 72, 79, 82, 73, 84, 89]', - }, - { - name: 'TREE_ROOT_SEED', - type: 'bytes', - value: '[84, 82, 69, 69, 95, 82, 79, 79, 84, 95, 83, 69, 69, 68]', - }, - { - name: 'STORAGE_SEED', - type: 'bytes', - value: '[115, 116, 111, 114, 97, 103, 101]', - }, - { - name: 'LEAVES_SEED', - type: 'bytes', - value: '[108, 101, 97, 118, 101, 115]', - }, - { - name: 'NULLIFIER_SEED', - type: 'bytes', - value: '[110, 102]', - }, - { - name: 'POOL_TYPE_SEED', - type: 'bytes', - value: '[112, 111, 111, 108, 116, 121, 112, 101]', - }, - { - name: 'POOL_CONFIG_SEED', - type: 'bytes', - value: '[112, 111, 111, 108, 45, 99, 111, 110, 102, 105, 103]', - }, - { - name: 'POOL_SEED', - type: 'bytes', - value: '[112, 111, 111, 108]', - }, - { - name: 'TOKEN_AUTHORITY_SEED', - type: 'bytes', - value: '[115, 112, 108]', - }, - ], - instructions: [ - { - name: 'initializeNewMerkleTreeSet', - docs: [ - 'Initializes a new Merkle tree from config bytes.', - 'Can only be called from the merkle_tree_authority.', - ], - accounts: [ - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'newMerkleTreeSet', - isMut: true, - isSigner: false, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'rent', - isMut: false, - isSigner: false, - }, - { - name: 'merkleTreeAuthorityPda', - isMut: true, - isSigner: false, - }, - ], - args: [], - }, - { - name: 'initializeMerkleTreeAuthority', - docs: [ - 'Initializes a new merkle tree authority which can register new verifiers and configure', - 'permissions to create new pools.', - ], - accounts: [ - { - name: 'merkleTreeAuthorityPda', - isMut: true, - isSigner: false, - }, - { - name: 'merkleTreeSet', - isMut: true, - isSigner: false, - }, - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'rent', - isMut: false, - isSigner: false, - }, - ], - args: [], - }, - { - name: 'updateMerkleTreeAuthority', - docs: ['Updates the merkle tree authority to a new authority.'], - accounts: [ - { - name: 'merkleTreeAuthorityPda', - isMut: true, - isSigner: false, - }, - { - name: 'authority', - isMut: false, - isSigner: true, - }, - { - name: 'newAuthority', - isMut: false, - isSigner: false, - }, - ], - args: [], - }, - { - name: 'enablePermissionlessSplTokens', - docs: ['Enables anyone to create token pools.'], - accounts: [ - { - name: 'merkleTreeAuthorityPda', - isMut: true, - isSigner: false, - }, - { - name: 'authority', - isMut: false, - isSigner: true, - }, - ], - args: [ - { - name: 'enablePermissionless', - type: 'bool', - }, - ], - }, - { - name: 'registerVerifier', - docs: [ - 'Registers a new verifier which can decompress tokens, insert new nullifiers, add new leaves.', - 'These functions can only be invoked from registered verifiers.', - ], - accounts: [ - { - name: 'registeredVerifierPda', - isMut: true, - isSigner: false, - }, - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'merkleTreeAuthorityPda', - isMut: false, - isSigner: false, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'rent', - isMut: false, - isSigner: false, - }, - ], - args: [ - { - name: 'verifierPubkey', - type: 'publicKey', - }, - ], - }, - { - name: 'registerPoolType', - docs: ['Registers a new pooltype.'], - accounts: [ - { - name: 'registeredPoolTypePda', - isMut: true, - isSigner: false, - }, - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'rent', - isMut: false, - isSigner: false, - }, - { - name: 'merkleTreeAuthorityPda', - isMut: false, - isSigner: false, - }, - ], - args: [ - { - name: 'poolType', - type: { - array: ['u8', 32], - }, - }, - ], - }, - { - name: 'registerSplPool', - docs: [ - 'Creates a new spl token pool which can be used by any registered verifier.', - ], - accounts: [ - { - name: 'registeredAssetPoolPda', - isMut: true, - isSigner: false, - }, - { - name: 'merkleTreePdaToken', - isMut: true, - isSigner: false, - }, - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'rent', - isMut: false, - isSigner: false, - }, - { - name: 'mint', - isMut: true, - isSigner: false, - }, - { - name: 'tokenAuthority', - isMut: true, - isSigner: false, - }, - { - name: 'tokenProgram', - isMut: false, - isSigner: false, - }, - { - name: 'registeredPoolTypePda', - isMut: false, - isSigner: false, - docs: ['Just needs to exist and be derived correctly.'], - }, - { - name: 'merkleTreeAuthorityPda', - isMut: true, - isSigner: false, - }, - ], - args: [], - }, - { - name: 'registerSolPool', - docs: [ - 'Creates a new sol pool which can be used by any registered verifier.', - ], - accounts: [ - { - name: 'registeredAssetPoolPda', - isMut: true, - isSigner: false, - }, - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'rent', - isMut: false, - isSigner: false, - }, - { - name: 'registeredPoolTypePda', - isMut: false, - isSigner: false, - }, - { - name: 'merkleTreeAuthorityPda', - isMut: true, - isSigner: false, - }, - ], - args: [], - }, - { - name: 'insertTwoLeaves', - docs: [ - 'Creates and initializes a pda which stores two merkle tree leaves and encrypted Utxos.', - 'The inserted leaves are not part of the Merkle tree yet and marked accordingly.', - 'The Merkle tree has to be updated after.', - 'Can only be called from a registered verifier program.', - ], - accounts: [ - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'merkleTreeSet', - isMut: true, - isSigner: false, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'registeredVerifierPda', - isMut: false, - isSigner: false, - }, - { - name: 'logWrapper', - isMut: false, - isSigner: false, - }, - ], - args: [ - { - name: 'leaves', - type: { - vec: { - array: ['u8', 32], - }, - }, - }, - ], - }, - { - name: 'insertTwoLeavesEvent', - accounts: [ - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'merkleTreeSet', - isMut: true, - isSigner: false, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'registeredVerifier', - isMut: false, - isSigner: false, - }, - ], - args: [ - { - name: 'leafLeft', - type: { - array: ['u8', 32], - }, - }, - { - name: 'leafRight', - type: { - array: ['u8', 32], - }, - }, - ], - }, - { - name: 'decompressSol', - docs: [ - 'Decompresses sol from a liquidity pool.', - 'An arbitrary number of recipients can be passed in with remaining accounts.', - 'Can only be called from a registered verifier program.', - ], - accounts: [ - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'merkleTreeToken', - isMut: true, - isSigner: false, - }, - { - name: 'registeredVerifierPda', - isMut: true, - isSigner: false, - }, - { - name: 'recipient', - isMut: true, - isSigner: false, - }, - ], - args: [ - { - name: 'amount', - type: 'u64', - }, - ], - }, - { - name: 'decompressSpl', - docs: [ - 'Decompresses spl tokens from a liquidity pool.', - 'An arbitrary number of recipients can be passed in with remaining accounts.', - 'Can only be called from a registered verifier program.', - ], - accounts: [ - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'merkleTreeToken', - isMut: true, - isSigner: false, - }, - { - name: 'recipient', - isMut: true, - isSigner: false, - }, - { - name: 'tokenProgram', - isMut: false, - isSigner: false, - }, - { - name: 'tokenAuthority', - isMut: true, - isSigner: false, - }, - { - name: 'registeredVerifierPda', - isMut: false, - isSigner: false, - }, - ], - args: [ - { - name: 'amount', - type: 'u64', - }, - ], - }, - { - name: 'initializeNullifiers', - accounts: [ - { - name: 'authority', - isMut: true, - isSigner: true, - }, - { - name: 'systemProgram', - isMut: false, - isSigner: false, - }, - { - name: 'registeredVerifierPda', - isMut: false, - isSigner: false, - }, - ], - args: [ - { - name: 'nullifiers', - type: { - vec: { - array: ['u8', 32], - }, - }, - }, - ], - }, - ], - accounts: [ - { - name: 'registeredAssetPool', - docs: [ - 'Nullfier pdas are derived from the nullifier', - 'existence of a nullifier is the check to prevent double spends.', - ], - type: { - kind: 'struct', - fields: [ - { - name: 'assetPoolPubkey', - type: 'publicKey', - }, - { - name: 'poolType', - type: { - array: ['u8', 32], - }, - }, - { - name: 'index', - type: 'u64', - }, - ], - }, - }, - { - name: 'registeredPoolType', - docs: ['Pool type'], - type: { - kind: 'struct', - fields: [ - { - name: 'poolType', - type: { - array: ['u8', 32], - }, - }, - ], - }, - }, - { - name: 'merkleTreeAuthority', - docs: [ - 'Configures the authority of the merkle tree which can:', - '- register new verifiers', - '- register new asset pools', - '- register new asset pool types', - '- set permissions for new asset pool creation', - '- keeps current highest index for assets and merkle trees to enable lookups of these', - ], - type: { - kind: 'struct', - fields: [ - { - name: 'pubkey', - type: 'publicKey', - }, - { - name: 'merkleTreeSetIndex', - type: 'u64', - }, - { - name: 'registeredAssetIndex', - type: 'u64', - }, - { - name: 'enablePermissionlessSplTokens', - type: 'bool', - }, - { - name: 'enablePermissionlessMerkleTreeRegistration', - type: 'bool', - }, - ], - }, - }, - { - name: 'registeredVerifier', - docs: [''], - type: { - kind: 'struct', - fields: [ - { - name: 'pubkey', - type: 'publicKey', - }, - ], - }, - }, - { - name: 'merkleTreeSet', - docs: ['Set of on-chain Merkle trees.'], - type: { - kind: 'struct', - fields: [ - { - name: 'index', - docs: ['Unique index.'], - type: 'u64', - }, - { - name: 'nextMerkleTree', - docs: ['Public key of the next Merkle tree set.'], - type: 'publicKey', - }, - { - name: 'owner', - docs: ['Owner of the Merkle tree set.'], - type: 'publicKey', - }, - { - name: 'stateMerkleTree', - docs: ['Merkle tree for the transaction state.'], - type: { - array: ['u8', 90368], - }, - }, - { - name: 'eventMerkleTree', - docs: ['Merkle tree for event compression.'], - type: { - array: ['u8', 90368], - }, - }, - ], - }, - }, - ], - errors: [ - { - code: 6000, - name: 'MtTmpPdaInitFailed', - msg: 'Merkle tree tmp account init failed wrong pda.', - }, - { - code: 6001, - name: 'MerkleTreeInitFailed', - msg: 'Merkle tree tmp account init failed.', - }, - { - code: 6002, - name: 'ContractStillLocked', - msg: 'Contract is still locked.', - }, - { - code: 6003, - name: 'InvalidMerkleTree', - msg: 'InvalidMerkleTree.', - }, - { - code: 6004, - name: 'InvalidMerkleTreeOwner', - msg: 'InvalidMerkleTreeOwner.', - }, - { - code: 6005, - name: 'PubkeyCheckFailed', - msg: 'PubkeyCheckFailed', - }, - { - code: 6006, - name: 'CloseAccountFailed', - msg: 'CloseAccountFailed', - }, - { - code: 6007, - name: 'DecompressFailed', - msg: 'DecompressFailed', - }, - { - code: 6008, - name: 'MerkleTreeUpdateNotInRootInsert', - msg: 'MerkleTreeUpdateNotInRootInsert', - }, - { - code: 6009, - name: 'MerkleTreeUpdateNotInRootInsertState', - msg: 'MerkleTreeUpdateNotInRootInsert', - }, - { - code: 6010, - name: 'InvalidNumberOfLeaves', - msg: 'InvalidNumberOfLeaves', - }, - { - code: 6011, - name: 'LeafAlreadyInserted', - msg: 'LeafAlreadyInserted', - }, - { - code: 6012, - name: 'WrongLeavesLastTx', - msg: 'WrongLeavesLastTx', - }, - { - code: 6013, - name: 'FirstLeavesPdaIncorrectIndex', - msg: 'FirstLeavesPdaIncorrectIndex', - }, - { - code: 6014, - name: 'NullifierAlreadyExists', - msg: 'NullifierAlreadyExists', - }, - { - code: 6015, - name: 'LeavesOfWrongTree', - msg: 'LeavesOfWrongTree', - }, - { - code: 6016, - name: 'InvalidAuthority', - msg: 'InvalidAuthority', - }, - { - code: 6017, - name: 'InvalidVerifier', - msg: 'InvalidVerifier', - }, - { - code: 6018, - name: 'PubkeyTryFromFailed', - msg: 'PubkeyTryFromFailed', - }, - { - code: 6019, - name: 'ExpectedOldMerkleTrees', - msg: 'Expected old Merkle trees as remaining account.', - }, - { - code: 6020, - name: 'InvalidOldMerkleTree', - msg: 'Invalid old Merkle tree account.', - }, - { - code: 6021, - name: 'NotNewestOldMerkleTree', - msg: 'Provided old Merkle tree is not the newest one.', - }, - { - code: 6022, - name: 'ExpectedTwoLeavesPda', - msg: 'Expected two leaves PDA as a remaining account.', - }, - { - code: 6023, - name: 'InvalidTwoLeavesPda', - msg: 'Invalid two leaves PDA.', - }, - { - code: 6024, - name: 'OddNumberOfLeaves', - msg: 'Odd number of leaves.', - }, - { - code: 6025, - name: 'IntegerOverflow', - msg: 'Integer overflow, value too large', - }, - { - code: 6026, - name: 'InvalidNoopPubkey', - msg: 'Provided noop program public key is invalid', - }, - { - code: 6027, - name: 'EventNoChangelogEntry', - msg: 'Emitting an event requires at least one changelog entry', - }, - ], -}; diff --git a/js/stateless.js/src/idls/psp_compressed_pda.ts b/js/stateless.js/src/idls/psp_compressed_pda.ts index b83ab76ecd..7f442bfd54 100644 --- a/js/stateless.js/src/idls/psp_compressed_pda.ts +++ b/js/stateless.js/src/idls/psp_compressed_pda.ts @@ -1,7 +1,39 @@ export type PspCompressedPda = { version: '0.3.0'; name: 'psp_compressed_pda'; + constants: [ + { + name: 'COMPRESSED_SOL_PDA_SEED'; + type: 'bytes'; + value: '[99, 111, 109, 112, 114, 101, 115, 115, 101, 100, 95, 115, 111, 108, 95, 112, 100, 97]'; + }, + ]; instructions: [ + { + name: 'initCompressSolPda'; + docs: [ + 'Initializes the compressed sol pda.', + 'This pda is used to store compressed sol for the protocol.', + ]; + accounts: [ + { + name: 'feePayer'; + isMut: true; + isSigner: true; + }, + { + name: 'compressedSolPda'; + isMut: true; + isSigner: false; + }, + { + name: 'systemProgram'; + isMut: false; + isSigner: false; + }, + ]; + args: []; + }, { name: 'executeCompressedTransaction'; docs: [ @@ -47,6 +79,24 @@ export type PspCompressedPda = { isSigner: false; isOptional: true; }, + { + name: 'compressedSolPda'; + isMut: true; + isSigner: false; + isOptional: true; + }, + { + name: 'deCompressRecipient'; + isMut: true; + isSigner: false; + isOptional: true; + }, + { + name: 'systemProgram'; + isMut: false; + isSigner: false; + isOptional: true; + }, ]; args: [ { @@ -60,6 +110,13 @@ export type PspCompressedPda = { }, ]; accounts: [ + { + name: 'compressedSolPda'; + type: { + kind: 'struct'; + fields: []; + }; + }, { name: 'cpiSignatureAccount'; docs: [ @@ -226,7 +283,7 @@ export type PspCompressedPda = { type: 'bool'; }, { - name: 'deCompressAmount'; + name: 'deCompressLamports'; type: { option: 'u64'; }; @@ -316,6 +373,16 @@ export type PspCompressedPda = { option: 'u64'; }; }, + { + name: 'deCompressLamports'; + type: { + option: 'u64'; + }; + }, + { + name: 'isCompress'; + type: 'bool'; + }, ]; }; }, @@ -457,13 +524,75 @@ export type PspCompressedPda = { name: 'DeriveAddressError'; msg: 'DeriveAddressError'; }, + { + code: 6022; + name: 'CompressSolTransferFailed'; + msg: 'CompressSolTransferFailed'; + }, + { + code: 6023; + name: 'CompressedSolPdaUndefinedForCompressSol'; + msg: 'CompressedSolPdaUndefinedForCompressSol'; + }, + { + code: 6024; + name: 'DeCompressLamportsUndefinedForCompressSol'; + msg: 'DeCompressLamportsUndefinedForCompressSol'; + }, + { + code: 6025; + name: 'CompressedSolPdaUndefinedForDecompressSol'; + msg: 'CompressedSolPdaUndefinedForDecompressSol'; + }, + { + code: 6026; + name: 'DeCompressLamportsUndefinedForDecompressSol'; + msg: 'DeCompressLamportsUndefinedForDecompressSol'; + }, + { + code: 6027; + name: 'DecompressRecipientUndefinedForDecompressSol'; + msg: 'DecompressRecipientUndefinedForDecompressSol'; + }, ]; }; export const IDL: PspCompressedPda = { version: '0.3.0', name: 'psp_compressed_pda', + constants: [ + { + name: 'COMPRESSED_SOL_PDA_SEED', + type: 'bytes', + value: '[99, 111, 109, 112, 114, 101, 115, 115, 101, 100, 95, 115, 111, 108, 95, 112, 100, 97]', + }, + ], instructions: [ + { + name: 'initCompressSolPda', + docs: [ + 'Initializes the compressed sol pda.', + 'This pda is used to store compressed sol for the protocol.', + ], + accounts: [ + { + name: 'feePayer', + isMut: true, + isSigner: true, + }, + { + name: 'compressedSolPda', + isMut: true, + isSigner: false, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [], + }, { name: 'executeCompressedTransaction', docs: [ @@ -509,6 +638,24 @@ export const IDL: PspCompressedPda = { isSigner: false, isOptional: true, }, + { + name: 'compressedSolPda', + isMut: true, + isSigner: false, + isOptional: true, + }, + { + name: 'deCompressRecipient', + isMut: true, + isSigner: false, + isOptional: true, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + isOptional: true, + }, ], args: [ { @@ -522,6 +669,13 @@ export const IDL: PspCompressedPda = { }, ], accounts: [ + { + name: 'compressedSolPda', + type: { + kind: 'struct', + fields: [], + }, + }, { name: 'cpiSignatureAccount', docs: [ @@ -688,7 +842,7 @@ export const IDL: PspCompressedPda = { type: 'bool', }, { - name: 'deCompressAmount', + name: 'deCompressLamports', type: { option: 'u64', }, @@ -778,6 +932,16 @@ export const IDL: PspCompressedPda = { option: 'u64', }, }, + { + name: 'deCompressLamports', + type: { + option: 'u64', + }, + }, + { + name: 'isCompress', + type: 'bool', + }, ], }, }, @@ -919,5 +1083,35 @@ export const IDL: PspCompressedPda = { name: 'DeriveAddressError', msg: 'DeriveAddressError', }, + { + code: 6022, + name: 'CompressSolTransferFailed', + msg: 'CompressSolTransferFailed', + }, + { + code: 6023, + name: 'CompressedSolPdaUndefinedForCompressSol', + msg: 'CompressedSolPdaUndefinedForCompressSol', + }, + { + code: 6024, + name: 'DeCompressLamportsUndefinedForCompressSol', + msg: 'DeCompressLamportsUndefinedForCompressSol', + }, + { + code: 6025, + name: 'CompressedSolPdaUndefinedForDecompressSol', + msg: 'CompressedSolPdaUndefinedForDecompressSol', + }, + { + code: 6026, + name: 'DeCompressLamportsUndefinedForDecompressSol', + msg: 'DeCompressLamportsUndefinedForDecompressSol', + }, + { + code: 6027, + name: 'DecompressRecipientUndefinedForDecompressSol', + msg: 'DecompressRecipientUndefinedForDecompressSol', + }, ], }; diff --git a/js/stateless.js/src/instruction/pack-compressed-accounts.ts b/js/stateless.js/src/instruction/pack-compressed-accounts.ts index 805093ffd9..e15f086d02 100644 --- a/js/stateless.js/src/instruction/pack-compressed-accounts.ts +++ b/js/stateless.js/src/instruction/pack-compressed-accounts.ts @@ -92,6 +92,7 @@ export function packCompressedAccounts( _remainingAccounts, account.merkleTree, ); + const nullifierQueuePubkeyIndex = getIndexOrAdd( _remainingAccounts, account.nullifierQueue, diff --git a/js/stateless.js/src/programs/compressed-pda.ts b/js/stateless.js/src/programs/compressed-pda.ts index 0495fc99c4..3e5d0cdfb4 100644 --- a/js/stateless.js/src/programs/compressed-pda.ts +++ b/js/stateless.js/src/programs/compressed-pda.ts @@ -6,6 +6,7 @@ import { TransactionInstruction, AccountMeta, ComputeBudgetProgram, + SystemProgram, } from '@solana/web3.js'; import { IDL, PspCompressedPda } from '../idls/psp_compressed_pda'; import { useWallet } from '../wallet'; @@ -22,8 +23,9 @@ import { validateSameOwner, validateSufficientBalance, } from '../utils/validation'; +import { placeholderValidityProof } from '../test-utils'; -const sumupLamports = (accounts: CompressedAccountWithMerkleContext[]): BN => { +const sumUpLamports = (accounts: CompressedAccountWithMerkleContext[]): BN => { return accounts.reduce( (acc, account) => acc.add(bn(account.lamports)), bn(0), @@ -70,6 +72,74 @@ type TransferParams = { outputStateTrees?: PublicKey[] | PublicKey; }; +/// TODO: +/// - add option to compress to another owner +/// - add option to merge with input state +/** + * Defines the parameters for the transfer method + */ +type CompressParams = { + /** + * The payer of the transaction. + */ + payer: PublicKey; + /** + * address that the lamports are attached to. also defaults to the recipient owner + */ + address: PublicKey; + /** + * amount of lamports to compress. + */ + lamports: number | BN; + /** + * The state tree that the tx output should be inserted into. This can be a + * + */ + outputStateTree: PublicKey; +}; + +/** + * Defines the parameters for the transfer method + */ +type DecompressParams = { + /** + * The payer of the transaction. + */ + payer: PublicKey; + /** + * The input state to be consumed. + */ + inputCompressedAccounts: CompressedAccountWithMerkleContext[]; + /** + * Recipient address of uncompressed lamports + */ + toAddress: PublicKey; + /** + * amount of lamports to decompress. + */ + lamports: number | BN; + /** + * The recent state root indices of the input state. The expiry is tied to + * the proof. + * + * TODO: Add support for passing recent-values after instruction creation. + */ + recentInputStateRootIndices: number[]; + /** + * The recent validity proof for state inclusion of the input state. It + * expires after n slots. + */ + recentValidityProof: CompressedProof; + /** + * The state trees that the tx output should be inserted into. This can be a + * single PublicKey or an array of PublicKey. Defaults to the 0th state tree + * of input state. + */ + outputStateTree?: PublicKey; +}; + +const COMPRESSED_SOL_PDA_SEED = Buffer.from('compressed_sol_pda'); + export class LightSystemProgram { /** * @internal @@ -93,6 +163,18 @@ export class LightSystemProgram { return this._program!; } + /** + * @internal + * Cwct1kQLwJm8Z3HetLu8m4SXkhD6FZ5fXbJQCxTxPnGY + */ + static deriveCompressedSolPda(): PublicKey { + const seeds = [COMPRESSED_SOL_PDA_SEED]; + const [address, _] = PublicKey.findProgramAddressSync( + seeds, + this.programId, + ); + return address; + } /** * Initializes the program statically if not already initialized. */ @@ -122,7 +204,7 @@ export class LightSystemProgram { lamports: number | BN, ): CompressedAccount[] { lamports = bn(lamports); - const inputLamports = sumupLamports(inputCompressedAccounts); + const inputLamports = sumUpLamports(inputCompressedAccounts); const changeLamports = inputLamports.sub(lamports); validateSufficientBalance(changeLamports); @@ -143,6 +225,32 @@ export class LightSystemProgram { return outputCompressedAccounts; } + static createDecompressOutputState( + inputCompressedAccounts: CompressedAccountWithMerkleContext[], + lamports: number | BN, + ): CompressedAccount[] { + lamports = bn(lamports); + const inputLamports = sumUpLamports(inputCompressedAccounts); + const changeLamports = inputLamports.sub(lamports); + + validateSufficientBalance(changeLamports); + + /// lamports gets decompressed + if (changeLamports.eq(bn(0))) { + return []; + } + + validateSameOwner(inputCompressedAccounts); + + const outputCompressedAccounts: CompressedAccount[] = [ + createCompressedAccount( + inputCompressedAccounts[0].owner, + changeLamports, + ), + ]; + return outputCompressedAccounts; + } + /** * Creates a transaction instruction that transfers compressed lamports from * one owner to another. @@ -195,14 +303,203 @@ export class LightSystemProgram { outputStateMerkleTreeIndices, ), relayFee: null, + deCompressLamports: null, + isCompress: false, + }, + ); + + /// Format accounts + const staticAccounts = { + ...defaultStaticAccountsStruct(), + signer: payer, + invokingProgram: this.programId, + compressedSolPda: null, + deCompressRecipient: null, + systemProgram: null, + }; + + const remainingAccountMetas = remainingAccounts.map( + (account): AccountMeta => ({ + pubkey: account, + isWritable: true, + isSigner: false, + }), + ); + + /// Build anchor instruction + const instruction = await this.program.methods + .executeCompressedTransaction(data) + .accounts(staticAccounts) + .remainingAccounts(remainingAccountMetas) + .instruction(); + + const instructions = [ + ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }), + instruction, + ]; + + return instructions; + } + + /** + * Initialize the compressed sol pda + */ + static async initCompressedSolPda( + feePayer: PublicKey, + ): Promise { + const accounts = { + feePayer, + compressedSolPda: this.deriveCompressedSolPda(), + systemProgram: SystemProgram.programId, + }; + + const instruction = await this.program.methods + .initCompressSolPda() + .accounts(accounts) + .instruction(); + return instruction; + } + + /** + * Creates a transaction instruction that transfers compressed lamports from + * one owner to another. + */ + static async compress( + params: CompressParams, + ): Promise { + const { payer, outputStateTree, address } = params; + + /// Create output state + const lamports = bn(params.lamports); + const outputCompressedAccount = createCompressedAccount( + address, + lamports, + ); + + /// Pack accounts + const { + packedInputCompressedAccounts, + outputStateMerkleTreeIndices, + remainingAccounts, + } = packCompressedAccounts([], 1, outputStateTree); + + /// Encode instruction data + const data = this.program.coder.types.encode( + 'InstructionDataTransfer', + { + proof: placeholderValidityProof(), + inputRootIndices: [], + /// TODO: here and on-chain: option or similar. + newAddressSeeds: [], + addressQueueAccountIndices: Buffer.from([]), + addressMerkleTreeAccountIndices: Buffer.from([]), + addressMerkleTreeRootIndices: [], + inputCompressedAccountsWithMerkleContext: + packedInputCompressedAccounts, + outputCompressedAccounts: [outputCompressedAccount], + outputStateMerkleTreeAccountIndices: Buffer.from( + new Uint8Array(outputStateMerkleTreeIndices), + ), + relayFee: null, + deCompressLamports: lamports, + isCompress: true, + }, + ); + + /// TODO : refactor + /// Format accounts + const staticAccounts = { + ...defaultStaticAccountsStruct(), + signer: payer, + invokingProgram: this.programId, + compressedSolPda: this.deriveCompressedSolPda(), + deCompressRecipient: null, + systemProgram: SystemProgram.programId, + }; + + const remainingAccountMetas = remainingAccounts.map( + (account): AccountMeta => ({ + pubkey: account, + isWritable: true, + isSigner: false, + }), + ); + + /// Build anchor instruction + const instruction = await this.program.methods + .executeCompressedTransaction(data) + .accounts(staticAccounts) + .remainingAccounts(remainingAccountMetas) + .instruction(); + + const instructions = [ + ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }), + instruction, + ]; + + return instructions; + } + + /** + * Creates a transaction instruction that transfers compressed lamports from + * one owner to another. + */ + /// TODO: add check that outputStateTree is provided or supplemented if change exists + static async decompress( + params: DecompressParams, + ): Promise { + const { payer, outputStateTree, toAddress } = params; + + /// Create output state + const lamports = bn(params.lamports); + const outputCompressedAccounts = this.createDecompressOutputState( + params.inputCompressedAccounts, + lamports, + ); + + /// Pack accounts + const { + packedInputCompressedAccounts, + outputStateMerkleTreeIndices, + remainingAccounts, + } = packCompressedAccounts( + params.inputCompressedAccounts, + outputCompressedAccounts.length, + outputStateTree, + ); + + /// Encode instruction data + const data = this.program.coder.types.encode( + 'InstructionDataTransfer', + { + proof: params.recentValidityProof, + inputRootIndices: params.recentInputStateRootIndices, + /// TODO: here and on-chain: option or similar. + newAddressSeeds: [], + addressQueueAccountIndices: Buffer.from([]), + addressMerkleTreeAccountIndices: Buffer.from([]), + addressMerkleTreeRootIndices: [], + inputCompressedAccountsWithMerkleContext: + packedInputCompressedAccounts, + outputCompressedAccounts: outputCompressedAccounts, + outputStateMerkleTreeAccountIndices: Buffer.from( + new Uint8Array(outputStateMerkleTreeIndices), + ), + relayFee: null, + deCompressLamports: lamports, + isCompress: false, }, ); + /// TODO : refactor /// Format accounts const staticAccounts = { ...defaultStaticAccountsStruct(), signer: payer, invokingProgram: this.programId, + compressedSolPda: this.deriveCompressedSolPda(), + deCompressRecipient: toAddress, + systemProgram: SystemProgram.programId, }; const remainingAccountMetas = remainingAccounts.map( diff --git a/js/stateless.js/src/state/types.ts b/js/stateless.js/src/state/types.ts index 6a4a3bd5a0..b1e4c009bd 100644 --- a/js/stateless.js/src/state/types.ts +++ b/js/stateless.js/src/state/types.ts @@ -43,7 +43,7 @@ export interface PublicTransactionEvent { outputLeafIndices: number[]; // Vec relayFee: BN | null; // Option isCompress: boolean; // bool - deCompressAmount: BN | null; // Option + deCompressLamports: BN | null; // Option pubkeyArray: PublicKey[]; // Vec message: Uint8Array | null; // Option } @@ -55,6 +55,8 @@ export interface InstructionDataTransfer { outputCompressedAccounts: CompressedAccount[]; outputStateMerkleTreeAccountIndices: Buffer; // bytes // FIXME: into Vec on-chain relayFee: BN | null; // Option + deCompressLamports: BN | null; // Option + isCompression: boolean; // bool } export interface CompressedProof { diff --git a/js/stateless.js/src/utils/conversion.ts b/js/stateless.js/src/utils/conversion.ts index 0c45388f2b..962cda0b48 100644 --- a/js/stateless.js/src/utils/conversion.ts +++ b/js/stateless.js/src/utils/conversion.ts @@ -99,7 +99,7 @@ if (import.meta.vitest) { const buf = Buffer.from( '6500000000000000000000000000000000000000000000000000000000000000', 'hex', - ); + ).reverse(); expect(isSmallerThanBn254FieldSizeLe(buf)).toBe(false); }); }); @@ -117,7 +117,7 @@ if (import.meta.vitest) { 18, 44, ]; - it.only('should return a valid value for initial buffer', async () => { + it('should return a valid value for initial buffer', async () => { const result = await hashToBn254FieldSizeLe(Buffer.from(bytes)); expect(Array.from(result![0])).toEqual(refResult); @@ -132,7 +132,7 @@ if (import.meta.vitest) { expect(result).not.toBeNull(); if (result) { expect(result[0]).toBeInstanceOf(Buffer); - expect(result[1]).toBe(255); + expect(result[1]).toBe(254); } }); diff --git a/js/stateless.js/tests/e2e/compress.test.ts b/js/stateless.js/tests/e2e/compress.test.ts new file mode 100644 index 0000000000..37368239f2 --- /dev/null +++ b/js/stateless.js/tests/e2e/compress.test.ts @@ -0,0 +1,133 @@ +import { describe, it, assert, beforeAll } from 'vitest'; +import { + CompressedAccount, + CompressedAccountWithMerkleContext, + MerkleContext, + bn, +} from '../../src/state'; +import { sendAndConfirmTx, buildAndSignTx } from '../../src/utils'; + +import { Keypair, Signer } from '@solana/web3.js'; +import { defaultTestStateTreeAccounts } from '../../src/constants'; +import { getTestRpc, newAccountWithLamports } from '../../src/test-utils'; +import { LightSystemProgram, Rpc } from '../../src'; + +/// TODO: add test case for payer != address +describe('compress', () => { + const { merkleTree, nullifierQueue } = defaultTestStateTreeAccounts(); + let rpc: Rpc; + let payer: Signer; + let initAuthority: Signer; + + beforeAll(async () => { + rpc = await getTestRpc(); + payer = await newAccountWithLamports(rpc, 1e9, 200); + initAuthority = await newAccountWithLamports(rpc, 1e9); + }); + + it('should compress lamports and then decompress', async () => { + const compressLamports = 20; + const preCompressBalance = await rpc.getBalance(payer.publicKey); + assert.equal(preCompressBalance, 1e9); + + const ix = await LightSystemProgram.initCompressedSolPda( + initAuthority.publicKey, + ); + const { blockhash: initBlockhash } = await rpc.getLatestBlockhash(); + const signedInitTx = buildAndSignTx([ix], initAuthority, initBlockhash); + await sendAndConfirmTx(rpc, signedInitTx); + + const ixs = await LightSystemProgram.compress({ + payer: payer.publicKey, + address: payer.publicKey, + lamports: compressLamports, + outputStateTree: merkleTree, + }); + + /// Send + const { blockhash } = await rpc.getLatestBlockhash(); + const signedTx = buildAndSignTx(ixs, payer, blockhash); + await sendAndConfirmTx(rpc, signedTx); + + rpc = await getTestRpc(); + + // @ts-ignore + const indexedEvents = await rpc.getParsedEvents(); + assert.equal(indexedEvents.length, 2); + assert.equal(indexedEvents[0].inputCompressedAccounts.length, 0); + assert.equal(indexedEvents[0].outputCompressedAccounts.length, 1); + assert.equal( + Number(indexedEvents[0].outputCompressedAccounts[0].lamports), + compressLamports, + ); + assert.equal( + indexedEvents[0].outputCompressedAccounts[0].owner.toBase58(), + payer.publicKey.toBase58(), + ); + assert.equal(indexedEvents[0].outputCompressedAccounts[0].data, null); + const postCompressBalance = await rpc.getBalance(payer.publicKey); + assert.equal( + postCompressBalance, + preCompressBalance - compressLamports - 5000, + ); + + /// TODO: use test-rpc call to get the account + const inputAccount: CompressedAccount = + indexedEvents[0].outputCompressedAccounts[0]; + const inputAccountHash: number[] = + indexedEvents[0].outputCompressedAccountHashes[0]; + const inputAccountLeafIndex: number = + indexedEvents[0].outputLeafIndices[0]; + + const proof = await rpc.getValidityProof([bn(inputAccountHash)]); + + const merkleCtx: MerkleContext = { + merkleTree: merkleTree, // TODO: dynamic + nullifierQueue: nullifierQueue, // TODO: dynamic + hash: inputAccountHash, + leafIndex: inputAccountLeafIndex, + }; + const withCtx: CompressedAccountWithMerkleContext = { + ...inputAccount, + ...merkleCtx, + }; + + /// Decompress + const decompressLamports = 15; + const decompressRecipient = payer.publicKey; + + const decompressIx = await LightSystemProgram.decompress({ + payer: payer.publicKey, + toAddress: decompressRecipient, + outputStateTree: merkleTree, + inputCompressedAccounts: [withCtx], + recentValidityProof: proof.compressedProof, + recentInputStateRootIndices: proof.rootIndices, + lamports: decompressLamports, + }); + + const { blockhash: decompressBlockhash } = + await rpc.getLatestBlockhash(); + const signedDecompressTx = buildAndSignTx( + decompressIx, + payer, + decompressBlockhash, + ); + await sendAndConfirmTx(rpc, signedDecompressTx); + + //@ts-ignore + const indexedEvents2 = await rpc.getParsedEvents(); + assert.equal(indexedEvents2.length, 3); + assert.equal(indexedEvents2[0].inputCompressedAccounts.length, 1); + assert.equal(indexedEvents2[0].outputCompressedAccounts.length, 1); + assert.equal( + Number(indexedEvents2[0].outputCompressedAccounts[0].lamports), + compressLamports - decompressLamports, + ); + const postDecompressBalance = await rpc.getBalance(decompressRecipient); + assert.equal( + postDecompressBalance, + postCompressBalance + decompressLamports - 5000, + ); + }); +}); diff --git a/js/stateless.js/tests/e2e/transfer.test.ts b/js/stateless.js/tests/e2e/transfer.test.ts index e17dc532f7..5606594da1 100644 --- a/js/stateless.js/tests/e2e/transfer.test.ts +++ b/js/stateless.js/tests/e2e/transfer.test.ts @@ -26,9 +26,7 @@ describe('transfer', () => { payer = await newAccountWithLamports(rpc); bob = Keypair.generate(); }); - // Note: - // We don't compress SOL yet, therefore cannot spend utxos with value yet. - // TODO: add one run with with inputUtxo where lamports: 0 + /// TODO: add compression step into beforeAll. it('should send compressed lamports alice -> bob', async () => { const proof_mock = placeholderValidityProof(); diff --git a/scripts/push-stateless-js-idls.sh b/scripts/push-stateless-js-idls.sh index ab058a63af..30337cb5db 100755 --- a/scripts/push-stateless-js-idls.sh +++ b/scripts/push-stateless-js-idls.sh @@ -5,7 +5,7 @@ SOURCE_DIR="./target/types" DEST_DIR="./js" DEST_DIR_STATELESS="$DEST_DIR/stateless.js/src/idls" -FILES_TO_COPY=("account_compression.ts" "light.ts" "light_merkle_tree_program.ts" "psp_compressed_pda.ts" "user_registry.ts") +FILES_TO_COPY=("account_compression.ts" "light.ts" "psp_compressed_pda.ts" "user_registry.ts") # copy each type file into the respective location for FILE in "${FILES_TO_COPY[@]}"; do