1
1
import Foundation
2
2
3
3
public struct TransactionMessage {
4
- var instructions : [ TransactionInstruction ]
5
- var recentBlockhash : String
6
- var payerKey : PublicKey
4
+ public var instructions : [ TransactionInstruction ]
5
+ public var recentBlockhash : String
6
+ public var payerKey : PublicKey
7
7
8
8
public init ( instructions: [ TransactionInstruction ] , recentBlockhash: String , payerKey: PublicKey ) {
9
9
self . instructions = instructions
10
10
self . recentBlockhash = recentBlockhash
11
11
self . payerKey = payerKey
12
12
}
13
13
14
- // TODO: implement
15
- // static func decompile() {}
14
+ public static func decompile( message: VersionedMessage , addressLookupTableAccounts: [ AddressLookupTableAccount ] ) throws -> Self {
15
+ let header = message. header
16
+ let compiledInstructions = message. compiledInstructions
17
+ let recentBlockhash = message. recentBlockhash
18
+
19
+ let numRequiredSignatures = header. numRequiredSignatures
20
+ let numReadonlySignedAccounts = header. numReadonlySignedAccounts
21
+ let numReadonlyUnsignedAccounts = header. numReadonlyUnsignedAccounts
22
+
23
+ let numWritableSignedAccounts = numRequiredSignatures - numReadonlySignedAccounts
24
+ guard numWritableSignedAccounts > 0 else {
25
+ throw TransactionMessageError . invalidHeader
26
+ }
27
+
28
+ let numWritableUnsignedAccounts = message. staticAccountKeys. count - numRequiredSignatures - numReadonlyUnsignedAccounts
29
+ guard numWritableUnsignedAccounts >= 0 else {
30
+ throw TransactionMessageError . invalidHeader
31
+ }
32
+
33
+ guard let accountKeys = try ? message. getAccountKeys ( addressLookupTableAccounts: addressLookupTableAccounts) else {
34
+ throw TransactionMessageError . noAccountKeys
35
+ }
36
+
37
+ guard let payerKey = accountKeys [ 0 ] else {
38
+ throw TransactionMessageError . noPayerKey
39
+ }
40
+
41
+ var instructions : [ TransactionInstruction ] = [ ]
42
+ for compiledIx in compiledInstructions {
43
+ var keys : [ AccountMeta ] = [ ]
44
+ for keyIndex in compiledIx. accountKeyIndexes {
45
+ guard let pubkey = accountKeys [ Int ( keyIndex) ] else {
46
+ throw TransactionMessageError . keyNotFound
47
+ }
48
+
49
+ let isSigner = keyIndex < numRequiredSignatures
50
+ let isWritable : Bool
51
+ if isSigner {
52
+ isWritable = keyIndex < numWritableSignedAccounts
53
+ } else if keyIndex < accountKeys. staticAccountKeys. count {
54
+ isWritable = Int ( keyIndex) - numRequiredSignatures < numWritableUnsignedAccounts
55
+ } else {
56
+ let writableCount = accountKeys. accountKeysFromLookups!. writable. count
57
+ isWritable = Int ( keyIndex) - accountKeys. staticAccountKeys. count < writableCount
58
+ }
59
+
60
+ keys. append ( AccountMeta ( publicKey: pubkey, isSigner: isSigner, isWritable: isWritable) )
61
+ }
62
+
63
+ guard let programId = accountKeys [ Int ( compiledIx. programIdIndex) ] else {
64
+ throw TransactionMessageError . programIdNotFound
65
+ }
66
+
67
+ instructions. append ( TransactionInstruction ( keys: keys, programId: programId, data: compiledIx. data) )
68
+ }
69
+
70
+ return TransactionMessage ( instructions: instructions, recentBlockhash: recentBlockhash, payerKey: payerKey)
71
+ }
16
72
17
73
public func compileToLegacyMessage( ) throws -> Message {
18
74
try Transaction (
@@ -34,3 +90,11 @@ public struct TransactionMessage {
34
90
)
35
91
}
36
92
}
93
+
94
+ public enum TransactionMessageError : Error , Equatable {
95
+ case invalidHeader
96
+ case noAccountKeys
97
+ case noPayerKey
98
+ case keyNotFound
99
+ case programIdNotFound
100
+ }
0 commit comments