spb/os-vault Public
Self-custody, multi-chain crypto wallet for macOS. One recovery phrase, six chain families, zero API keys — nothing leaves your Mac.
Swift 96%
Shell 3.4%
Makefile 0.6%
1import Foundation2import TweetNacl34public enum TransactionVersion: Equatable {5 case v06 case legacy7}89public struct VersionedTransaction: Equatable {10 public var message: VersionedMessage11 public internal(set) var signatures: [Data]1213 public mutating func setRecentBlockHash(_ blockHash: BlockHash) {14 message.setRecentBlockHash(blockHash)15 }1617 public var version: TransactionVersion {18 message.value.version19 }2021 public init(message: VersionedMessage, signatures: [Data]? = nil) {22 self.message = message2324 if let signatures = signatures {25 self.signatures = signatures26 } else {27 var signatures: [Data] = []28 for _ in 0 ..< message.value.header.numRequiredSignatures {29 signatures.append(Constants.defaultSignature)30 }31 self.signatures = signatures32 }33 }3435 public func serialize() throws -> Data {36 let serializedMessage = try message.value.serialize()3738 let encodedSignaturesLength = Data.encodeLength(signatures.count)39 let signaturesData = signatures.reduce(Data(), +)4041 var serializedTransaction: Data = .init()42 serializedTransaction.append(encodedSignaturesLength)43 serializedTransaction.append(signaturesData)44 serializedTransaction.append(serializedMessage)4546 return serializedTransaction47 }4849 public static func deserialize(data: Data) throws -> Self {50 var byteArray = BinaryReader(bytes: data.bytes)5152 var signatures: [Data] = []53 let signaturesLength = try byteArray.decodeLength()54 for _ in 0 ..< signaturesLength {55 let signatureData = try byteArray.read(count: Constants.signatureLength)56 signatures.append(Data(signatureData))57 }5859 let versionedMessage = try VersionedMessage.deserialize(data: Data(byteArray.readAll()))6061 return .init(message: versionedMessage, signatures: signatures)62 }6364 public mutating func sign(signers: [KeyPair]) throws {65 let messageData = try message.value.serialize()66 let signerPubkeys = message.value.staticAccountKeys.prefix(message.value.header.numRequiredSignatures)6768 for signer in signers {69 guard let signerIndex = signerPubkeys.firstIndex(of: signer.publicKey) else {70 print("Cannot sign with non signer key \(signer.publicKey.base58EncodedString)")71 continue72 }73 signatures[signerIndex] = try NaclSign.signDetached(74 message: messageData,75 secretKey: signer.secretKey76 )77 }78 }7980 public mutating func addSignature(publicKey: PublicKey, signature: Data) throws {81 let signerPubkeys = Array(message.value.staticAccountKeys.prefix(message.value.header.numRequiredSignatures))8283 guard let signerIndex = signerPubkeys.firstIndex(of: publicKey) else {84 throw VersionedTransactionError.nonRequiredSigner(publicKey.base58EncodedString)85 }8687 signatures[signerIndex] = signature88 }89}90