-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathtransfer.ts
121 lines (114 loc) · 3.81 KB
/
transfer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { Pubkey } from '~/types/account';
import { DasApi } from '~/das-api';
import { debugLog, Result, Try } from '~/suite-utils';
import { Node } from '~/node';
import { createTransferInstruction } from 'mpl-bubblegum-instructions';
import {
ConcurrentMerkleTreeAccount,
SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
SPL_NOOP_PROGRAM_ID,
} from '@solana/spl-account-compression';
import { TransactionBuilder } from '~/transaction-builder';
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
import { CommonStructure } from '~/types/transaction-builder';
export namespace CompressedNft {
/**
* @internal
*/
export const createTransfer = async (
assetId: Pubkey,
assetIdOwner: Pubkey,
dest: Pubkey,
delegate?: Pubkey,
): Promise<TransactionInstruction> => {
const assetProof = await DasApi.getAssetProof(assetId);
debugLog('# assetProof: ', assetProof);
if (assetProof.isErr) {
throw assetProof.error;
} else if (assetProof.isOk && assetProof.value.proof.length === 0) {
throw Error('Proof is empty. May be set Regular NFT?');
}
const asset = await DasApi.getAsset(assetId);
debugLog('# asset: ', asset);
if (asset.isErr) {
throw asset.error;
} else if (asset.isOk && asset.value.ownership.owner !== assetIdOwner) {
throw Error(
`NFT is not owned by the expected owner: current: ${asset.value.ownership.owner}, expected: ${assetIdOwner}`,
);
}
debugLog('# assetProof: ', assetProof.value);
debugLog('# ownership: ', asset.value.ownership);
debugLog('# authorities: ', asset.value.authorities);
const compression = asset.value.compression;
const ownership = asset.value.ownership;
const proof = assetProof.value.proof;
const merkleTree = compression.tree.toPublicKey();
const treeAccount = await ConcurrentMerkleTreeAccount.fromAccountAddress(
Node.getConnection(),
merkleTree,
);
const treeAuthority = treeAccount.getAuthority();
const canopyDepth = treeAccount.getCanopyDepth();
const proofPath = proof
.map((node: string) => ({
pubkey: node.toPublicKey(),
isSigner: false,
isWritable: false,
}))
.slice(0, proof.length - (canopyDepth ? canopyDepth : 0));
const leafOwner = ownership.owner.toPublicKey();
const newLeafOwner = dest.toPublicKey();
const leafNonce = compression.leaf_id;
let leafDelegate: PublicKey;
if (delegate) {
leafDelegate = delegate.toPublicKey();
} else {
leafDelegate = ownership.delegate
? ownership.delegate.toPublicKey()
: leafOwner;
}
return createTransferInstruction(
{
merkleTree,
treeAuthority,
leafOwner,
leafDelegate,
newLeafOwner,
logWrapper: SPL_NOOP_PROGRAM_ID,
compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
anchorRemainingAccounts: proofPath,
},
{
root: [...assetProof.value.root.trim().toPublicKey().toBytes()],
dataHash: [...compression.data_hash.trim().toPublicKey().toBytes()],
creatorHash: [
...compression.creator_hash.trim().toPublicKey().toBytes(),
],
nonce: leafNonce,
index: leafNonce,
},
);
};
/**
* transfer nft
*
* @param {Pubkey} mint
* @param {Pubkey} owner
* @param {Pubkey} dest
* @param {Secret[]} ownerOrMultisig
* @return Promise<Result<Transaction, Error>>
*/
export const transfer = async (
mint: Pubkey,
owner: Pubkey,
dest: Pubkey,
ownerOrMultisig: Secret[],
): Promise<Result<CommonStructure, Error>> => {
return Try(async () => {
const keypairs = ownerOrMultisig.map((s) => s.toKeypair());
const inst = await createTransfer(mint, owner, dest);
return new TransactionBuilder.Common([inst], keypairs);
});
};
}