SPB Git

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%
3.0 KB · 90 lines swift
Raw Blame History
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