diff --git a/js/compressed-token/src/program.ts b/js/compressed-token/src/program.ts index 02e3eb90ae..b2b81fb986 100644 --- a/js/compressed-token/src/program.ts +++ b/js/compressed-token/src/program.ts @@ -1533,6 +1533,8 @@ export class CompressedTokenProgram { inputCompressedTokenAccounts, ); + const CHANGE_INDEX = featureFlags.isV2() ? 1 : 0; // TODO: find better solution. + const rawData: CompressedTokenInstructionDataApprove = { proof: recentValidityProof, mint, @@ -1540,8 +1542,8 @@ export class CompressedTokenProgram { cpiContext: null, delegate: toAddress, delegatedAmount: bn(amount), - delegateMerkleTreeIndex: 1, // TODO: find better solution. - changeAccountMerkleTreeIndex: 1, + delegateMerkleTreeIndex: CHANGE_INDEX, + changeAccountMerkleTreeIndex: CHANGE_INDEX, delegateLamports: null, }; @@ -1610,7 +1612,7 @@ export class CompressedTokenProgram { mint, inputTokenDataWithContext, cpiContext: null, - outputAccountMerkleTreeIndex: 2, // Because of the delegate account. + outputAccountMerkleTreeIndex: featureFlags.isV2() ? 2 : 1, }; const data = encodeRevokeInstructionData(rawData); diff --git a/js/stateless.js/src/constants.ts b/js/stateless.js/src/constants.ts index 4f58008a76..17aaefff13 100644 --- a/js/stateless.js/src/constants.ts +++ b/js/stateless.js/src/constants.ts @@ -3,13 +3,18 @@ import { Buffer } from 'buffer'; import { ConfirmOptions, PublicKey } from '@solana/web3.js'; import { TreeInfo, TreeType } from './state/types'; +export enum VERSION { + V1 = 'V1', + V2 = 'V2', +} + /** /** * @internal * Feature flags. Only use if you know what you are doing. */ export const featureFlags = { - version: 'V2' as 'V1' | 'V2', + version: VERSION.V1, isV2: () => featureFlags.version.toUpperCase() === 'V2', }; diff --git a/js/stateless.js/src/rpc.ts b/js/stateless.js/src/rpc.ts index f101bb563b..b7df40845b 100644 --- a/js/stateless.js/src/rpc.ts +++ b/js/stateless.js/src/rpc.ts @@ -86,6 +86,7 @@ import { LightWasm } from './test-helpers'; import { getAllStateTreeInfos, getStateTreeInfoByPubkey, + getTreeInfoByPubkey, } from './utils/get-state-tree-infos'; import { TreeInfo } from './state/types'; import { validateNumbersForProof } from './utils'; @@ -988,7 +989,7 @@ export class Rpc extends Connection implements CompressionApiInterface { treeInfos, featureFlags.isV2() ? (proof as any).treeContext.tree - : (proof as any).tree!, + : (proof as any).merkleTree, ); const value: MerkleContextWithMerkleProof = { hash: bn(proof.hash.toArray('be', 32)), @@ -1064,7 +1065,7 @@ export class Rpc extends Connection implements CompressionApiInterface { stateTreeInfo, bn(item.hash.toArray('be', 32)), item.leafIndex, - true, + false, ), item.owner, bn(item.lamports), @@ -1856,7 +1857,6 @@ export class Rpc extends Connection implements CompressionApiInterface { jsonRpcResultAndContext(ValidityProofResultV2), ); } else { - throw new Error('V1 is not supported'); res = create( unsafeRes, jsonRpcResultAndContext(ValidityProofResult), @@ -1876,44 +1876,63 @@ export class Rpc extends Connection implements CompressionApiInterface { } const value = res.result.value as any; - return { - value: { - compressedProof: value.compressedProof, - leaves: value.accounts - .map((r: any) => r.hash) - .concat(value.addresses.map((r: any) => r.address)), - roots: value.accounts - .map((r: any) => r.root) - .concat(value.addresses.map((r: any) => r.root)), - rootIndices: value.accounts - .map((r: any) => r.rootIndex.rootIndex) - .concat(value.addresses.map((r: any) => r.rootIndex)), - proveByIndices: value.accounts - .map((r: any) => r.rootIndex.proveByIndex) - .concat(value.addresses.map((r: any) => false)), - treeInfos: value.accounts - .map((r: any) => r.merkleContext) - .concat(value.addresses.map((r: any) => r.merkleContext)), - leafIndices: value.accounts - .map((r: any) => r.leafIndex) - .concat(value.addresses.map((r: any) => 0)), - }, - context: res.result.context, - }; - // TODO: enable with v1 support. - // return { - // value: { - // compressedProof: value.compressedProof, - // roots: value.roots, - // rootIndices: value.rootIndices.map((r: any) => r.rootIndex), - // leafIndices: value.leafIndices, - // leaves: value.leaves, - // treeInfos: value.merkleContexts, - // proveByIndices: value.rootIndices.map( - // (r: any) => r.proveByIndex, - // ), - // }, - // context: res.result.context, - // }; + + if (featureFlags.isV2()) { + return { + value: { + compressedProof: value.compressedProof, + leaves: value.accounts + .map((r: any) => r.hash) + .concat(value.addresses.map((r: any) => r.address)), + roots: value.accounts + .map((r: any) => r.root) + .concat(value.addresses.map((r: any) => r.root)), + rootIndices: value.accounts + .map((r: any) => r.rootIndex.rootIndex) + .concat(value.addresses.map((r: any) => r.rootIndex)), + proveByIndices: value.accounts + .map((r: any) => r.rootIndex.proveByIndex) + .concat(value.addresses.map((r: any) => false)), + treeInfos: value.accounts + .map((r: any) => r.merkleContext) + .concat( + value.addresses.map((r: any) => r.merkleContext), + ), + leafIndices: value.accounts + .map((r: any) => r.leafIndex) + .concat(value.addresses.map((r: any) => 0)), + }, + context: res.result.context, + }; + } else { + // Temporary fix for v1 backward compatibility. + const allInfos = await this.getStateTreeInfos(); + const infos = value.merkleTrees.map((r: PublicKey) => { + if (r.equals(defaultTestStateTreeAccounts().addressTree)) { + return { + tree: r, + queue: defaultTestStateTreeAccounts().addressQueue, + treeType: TreeType.AddressV1, + nextTreeInfo: null, + }; + } + return getTreeInfoByPubkey(allInfos, r); + }); + + return { + value: { + compressedProof: value.compressedProof, + roots: value.roots, + rootIndices: value.rootIndices.map((r: any) => r), + leafIndices: value.leafIndices, + leaves: value.leaves, + treeInfos: infos, + proveByIndices: value.rootIndices.map( + (r: any) => r.proveByIndex, + ), + }, + context: res.result.context, + }; + } } } diff --git a/js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts b/js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts index 651ca87a7c..7cabc08e5f 100644 --- a/js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts +++ b/js/stateless.js/src/test-helpers/test-rpc/test-rpc.ts @@ -339,10 +339,6 @@ export class TestRpc extends Connection implements CompressionApiInterface { const leafIndex = leaves.findIndex(leaf => bn(leaf).eq(hashes[i]), ); - // const stateTreeInfo = getStateTreeInfoByPubkey( - // cachedStateTreeInfos, - // tree, - // ); /// If leaf is part of current tree, return proof if (leafIndex !== -1) { diff --git a/js/stateless.js/tests/unit/utils/conversion.test.ts b/js/stateless.js/tests/unit/utils/conversion.test.ts index 7743029443..b71c2157ff 100644 --- a/js/stateless.js/tests/unit/utils/conversion.test.ts +++ b/js/stateless.js/tests/unit/utils/conversion.test.ts @@ -662,8 +662,6 @@ describe('convertInvokeCpiWithReadOnlyToInvoke', () => { // First account (from input_compressed_accounts) const firstAccount = result.inputCompressedAccountsWithMerkleContext[0]; expect(firstAccount.rootIndex).toBe(789); - console.log('result', result); - console.log('firstAccount', firstAccount); expect(firstAccount.readOnly).toBe(false); expect(firstAccount.compressedAccount.lamports).toEqual(new BN(2000));