Code Monkey home page Code Monkey logo

solana-swift's Introduction

SolanaSwift

Solana-blockchain client, written in pure swift.

Version License Platform Documentation Status

Breaking changes

v5.0

...

  • Remove deprecated typealias Mint, use SPLTokenMintState or Token2022MintState instead.
  • Remove deprecated typealias Wallet, use AccountBalance instead.
  • Support token 2022 via method getAccountBalances (See GetAccountBalancesTests).
  • Support token 2022 and Token2022Program. ... See more

v2.0

  • From v2.0.0 we officially omited Rx library and a lot of dependencies, thus we also adopt swift concurrency to solana-swift. What have been changed?
  • For those who still use SolanaSDK class, follow this link

Features

  • Supported swift concurrency (from 2.0.0)
  • Key pairs generation
  • Solana JSON RPC API
  • Create, sign transactions
  • Send, simulate transactions
  • Solana token list
  • Socket communication
  • OrcaSwapSwift
  • RenVMSwift
  • Token2022

Requirements

  • iOS 13 or later

Dependencies

  • TweetNacl
  • secp256k1.swift
  • Task_retrying

Installation

Cocoapods

SolanaSwift is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'SolanaSwift', '~> 5.0.0'

Swift package manager

...
dependencies: [
    ...
    .package(url: "https://github.com/p2p-org/solana-swift", from: "5.0.0")
],
...

How to use

Import

import SolanaSwift

Logger

Create a logger that confirm to SolanaSwiftLogger

import SolanaSwift

class MyCustomLogger: SolanaSwiftLogger {
    func log(event: String, data: String?, logLevel: SolanaSwiftLoggerLogLevel) {
        // Custom log goes here
    }
}

// AppDelegate or somewhere eles

let customLogger: SolanaSwiftLogger = MyCustomLogger()
SolanaSwift.Logger.setLoggers([customLogger])

AccountStorage

Create an SolanaAccountStorage for saving account's keyPairs (public and private key), for example: KeychainAccountStorage for saving into Keychain in production, or InMemoryAccountStorage for temporarily saving into memory for testing. The "CustomAccountStorage" must conform to protocol SolanaAccountStorage, which has 2 requirements: function for saving save(_ account:) throws and computed property account: Account? { get thrrows } for retrieving user's account.

Example:

import SolanaSwift
import KeychainSwift
struct KeychainAccountStorage: SolanaAccountStorage {
    let tokenKey = <YOUR_KEY_TO_STORE_IN_KEYCHAIN>
    func save(_ account: Account) throws {
        let data = try JSONEncoder().encode(account)
        keychain.set(data, forKey: tokenKey)
    }
    
    var account: Account? {
        guard let data = keychain.getData(tokenKey) else {return nil}
        return try JSONDecoder().decode(Account.self, from: data)
    }
}

struct InMemoryAccountStorage: SolanaAccountStorage {
    private var _account: Account?
    func save(_ account: Account) throws {
        _account = account
    }
    
    var account: Account? {
        _account
    }
}

Create an account (keypair)

let account = try await KeyPair(network: .mainnetBeta)
// optional
accountStorage.save(account)

Restore an account from a seed phrase (keypair)

let account = try await KeyPair(phrases: ["miracle", "hundred", ...], network: .mainnetBeta, derivablePath: ...)
// optional
accountStorage.save(account)

Solana RPC Client

APIClient for Solana JSON RPC API. See Documentation

Example:

import SolanaSwift

let endpoint = APIEndPoint(
    address: "https://api.mainnet-beta.solana.com",
    network: .mainnetBeta
)

// To get block height
let apiClient = JSONRPCAPIClient(endpoint: endpoint)
let result = try await apiClient.getBlockHeight()

// To get balance of the current account
guard let account = try? accountStorage.account?.publicKey.base58EncodedString else { throw UnauthorizedError }
let balance = try await apiClient.getBalance(account: account, commitment: "recent")

Wait for confirmation method.

// Wait for confirmation
let signature = try await blockChainClient.sendTransaction(...)
try await apiClient.waitForConfirmation(signature: signature, ignoreStatus: true) // transaction will be mark as confirmed after timeout no matter what status is when ignoreStatus = true
let signature2 = try await blockchainClient.sendTransaction(/* another transaction that requires first transaction to be completed */)

Observe signature status. In stead of using socket to observe signature status, which is not really reliable (socket often returns signature status == finalized when it is not fully finalized), we observe its status by periodically sending getSignatureStatuses (with observeSignatureStatus method)

// Observe signature status with `observeSignatureStatus` method
var statuses = [TransactionStatus]()
for try await status in apiClient.observeSignatureStatus(signature: "jaiojsdfoijvaij", timeout: 60, delay: 3) {
    print(status)
    statuses.append(status)
}
// statuses.last == .sending // the signature is not confirmed
// statuses.last?.numberOfConfirmations == x // the signature is confirmed by x nodes (partially confirmed)
// statuses.last == .finalized // the signature is confirmed by all nodes

Batch support

// Batch request with different types
let req1: JSONRPCAPIClientRequest<AnyDecodable> = JSONRPCAPIClientRequest(method: "getAccountInfo", params: ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"])
let req2: JSONRPCAPIClientRequest<AnyDecodable> = JSONRPCAPIClientRequest(method: "getBalance", params: ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"])
let response = try await apiClient.batchRequest(with: [req1, req2])

// Batch request with same type
let balances: [Rpc<UInt64>?] = try await apiClient.batchRequest(method: "getBalance", params: [["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"], ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"], ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"]])

For the method that is not listed, use generic method request(method:params:) or request(method:) without params.

let result: String = try await apiClient.request(method: "getHealth")
XCTAssertEqual(result, "ok")

Solana Blockchain Client

Prepare, send and simulate transactions. See Documentation

Example:

import SolanaSwift

let blockchainClient = BlockchainClient(apiClient: JSONRPCAPIClient(endpoint: endpoint))

/// Prepare any transaction, use any Solana program to create instructions, see section Solana program. 
let preparedTransaction = try await blockchainClient.prepareTransaction(
    instructions: [...],
    signers: [...],
    feePayer: ...
)

/// SPECIAL CASE: Prepare Sending Native SOL
let preparedTransaction = try await blockchainClient.prepareSendingNativeSOL(
    account: account,
    to: toPublicKey,
    amount: 0
)

/// SPECIAL CASE: Sending SPL Tokens
let preparedTransactions = try await blockchainClient.prepareSendingSPLTokens(
    account: account,
    mintAddress: <SPL TOKEN MINT ADDRESS>,  // USDC mint
    decimals: 6,
    from: <YOUR SPL TOKEN ADDRESS>, // Your usdc address
    to: destination,
    amount: <AMOUNT IN LAMPORTS>
)

/// Simulate or send

blockchainClient.simulateTransaction(
    preparedTransaction: preparedTransaction
)

blockchainClient.sendTransaction(
    preparedTransaction: preparedTransaction
)

Solana Program

List of default programs and pre-defined method that live on Solana network:

  1. SystemProgram. See Documentation
  2. TokenProgram. See Documentation
  3. AssociatedTokenProgram. See Documentation
  4. OwnerValidationProgram. See Documentation
  5. TokenSwapProgram. See Documentation
  6. Token2022Program. See Documentation

Solana Tokens Repository

Tokens repository usefull when you need to get a list of tokens. See Documentation

Example:

let tokenRepository = TokensRepository(endpoint: endpoint)
let list = try await tokenRepository.getTokensList()

TokenRepository be default uses cache not to make extra calls, it can disabled manually .getTokensList(useCache: false)

Contribution

  • Welcome to contribute, feel free to change and open a PR.

Author

Chung Tran, [email protected]

License

SolanaSwift is available under the MIT license. See the LICENSE file for more info.

solana-swift's People

Contributors

basememara avatar bigearsenal avatar filozoff avatar martinlasek avatar nickshtefan avatar oldcrab avatar qwerkly avatar raulriera avatar sidorov-panda avatar trgilong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

solana-swift's Issues

Transaction from buffer crashed

    let swapTransaction = "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAHE6qKuts57bO2mg6cbj30QT4A3skmECnYiUVLCsOTirdeCgUkQaFYTleMcAX2p74eBXQZd1dwDyQZAPJfSv2KGc4W3FfOv2Xk+oeN6f/J0NU72gYddLzELx4G5UGmCxeNgj8R1MPvyuvS2qXi6VM9UWstHrV+HUZwbaukvr0Q0WY9Q+6gPplbNhPv+SK6XOQSX8+FMvOyP12TWA3oJ+XkLeVG4Udk5e5oReTsPZ52w8mzs3/ivxQXTupZBJzIVPHw/k54rg5UE6ZjmyUBpObjmq0QBWuBNpLrILwzSDuKyv2HXAcVuklgKT/VF1QWEnmrf7ArRq42XRiUkdWIZYgEfrNuCHH/POhqrZBNawsW/vjZ0w5tXghOCOpXZOYKLcemsLmFrjy6CB49a7T3SzV9/jKgKMC9Qt5n5ypgWf4B2TlNyVrr4IBnDfDn1F4pIswzwRa4dcMGijQHlQPLvHCWcnbb0Qs6UV6mEE7Jw0D1r3D9NZXd6iIwj4TsasfYvhotfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAEedVb8jHAbu50xW7OaBUH/bGy3qP0jlECsc2iVrwTjwbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpjJclj04kifG7PRApFI4NgwtaE5na/xCEBI572Nvp+Fm0P/on9df2SnTAmx8pWHneSwmrNt/J3VFLMhqns4zl6OL4d+g9rsaIj0Orta57MRu3jDSWCJf85ae4LBbiD/GX9tnJbfcDAMPlrdqyxs23gNR9+Snk0dv5uKt9vG+rsqgIDQAFAjSEBgANAAkDr5IDAAAAAAAQBgACACUMDwEBDAIAAgwCAAAAgJaYAAAAAAAPAQIBERAGAAcAKAwPAQEOOg8SAAIBCgclKA4OEQ4mEicdAQMaGBkPCBwbCw4jDxMiFBUXJBYTExMTExMDCRIhDxIeCiAJHwQFBiktwSCbM0HWnIEAAwAAABpkAAEHZAECEQBkAgOAlpgAAAAAAAgCky4AAAAAMgAADwMCAAABCQNciv9l8mgl8j6Fd6xh+aVvmEOc54Bo9QVJ10TmSZpG0gXr6uzo6QQqCwxGVy4M7t45sy4vc4DaiT7ps5V5J3MYJmWX01fgbyZiOTcGlMPCx8TJA+nGyFVVKMyqsvHK2ZNsvoVS7mHQL2FekI0eZHSdNlR6FTuiA6SjoQKQpg=="
    let data = Data(base64Encoded: swapTransaction)
    let transaction = try Transaction.from(data: data!)

Transaction simulation failed

So thats is my code (again)

       private func transferSolanaToken(mnemonic: [String], wallet: HDWallet) {
        try async {
            let endpoint = APIEndPoint(
                address: "https://api.mainnet-beta.solana.com",
                network: .mainnetBeta
            )
            do {
                let account = try await Account(phrase: mnemonic, network: .mainnetBeta, derivablePath: .default)
                let blockchainClient = BlockchainClient(apiClient: JSONRPCAPIClient(endpoint: endpoint))
                let preparedTransaction = try await blockchainClient.prepareSendingSPLTokens(
                    account: account,
                    mintAddress: "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2",  // USDC mint
                    decimals: 6,
                    from: "DnTwkxa6xtFB72w2t9PPrwuxksAR1Gb663UWTGLbVpYM", // Your usdc address
                    to: "W3LJP23kwe4Vt6E2cpZ5DRHSNiJxfYwTxg8zuTmTKAT",
                    amount: UInt64(1)
                )
                
                print(preparedTransaction)
                
                let result = try await blockchainClient.sendTransaction(preparedTransaction: 
          preparedTransaction.preparedTransaction)
                
                print(result)
            }
            catch let error {
                print(error)
            }
        }
     }

And error say

    responseError(SolanaSwift.ResponseError(code: Optional(-32002), message: Optional("Transaction simulation failed: 
    it an account but found no record of a prior credit."), data: Optional(SolanaSwift.ResponseErrorData(logs: Optional([]), 
    numSlotsBehind: nil))))

What it's mean, and how make it work?
Can anyone help me?
Ty

sendTransaction not working.

Hey, I am getting an error back when trying to execute a transaction.
Someone from the crypto community said I'd need to also send along

skipPreflight=true since it's by default false as per Solana Documentation.

However this SDK does not provide the option to set the skipPreflight to true.

{
  "jsonrpc": "2.0",
    "error": {
      "code": -32002,
      "message": "Transaction simulation failed: Error processing Instruction 2: custom program error: 0xbc4",
      ...
    }
  }
}

Get Token Balance Issue

I want to get tokens balance on devnet. I am using getTokenAccountBalance method by public key but it doesn't return balance. Show "boringssl_metrics_log_metric_block_invoke(151) Failed to log metrics" error.

I am using getBalance method to get wallet balance its working.

How can I get token balance?

Batched example seems broken

Description

When trying to example in the README file about batched requests, it fails due to a Decoder issue

let req1: JSONRPCAPIClientRequest<AnyDecodable> = JSONRPCAPIClientRequest(method: "getAccountInfo", params: ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"])
let req2: JSONRPCAPIClientRequest<AnyDecodable> = JSONRPCAPIClientRequest(method: "getBalance", params: ["63ionHTAM94KaSujUCg23hfg7TLharchq5BYXdLGqia1"])
let response = try! await apiClient.batchRequest(with: [req1, req2])
Thread 3: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))

'Task' is only available in iOS 15.0 or newer

When i do pod instal with your lib, my project say <'Task' is only available in iOS 15.0 or newer>
but i already change deployment target to IOS 15, and it still <'Task' is only available in iOS 15.0 or newer>

Change log: 1.x.x to 2.x.x

Edited

  • SolanaSDK namespace will be marked as deprecated, new classes, modules will be implemented without namespace.
  • Better logger has to be integrated

The problems and their solutions

1. Highly coupled features in SolanaSwift library

Problem

Due to lack of knowledges and documentation about Solana blockchain at the beginning of the development, the network client module, blockchain client module and other module are highly coupled in one class SolanaSDK, which is inconvenient for using and really hard to test.

For example: For retrieving list of supported token or calling getBalance for an account, the class SolanaSDK needs to be initialized first. As a result, all another modules has to be initialized too, including AccountStorage, which requires user to authenticate, even the SolanaRPC does not require authorization.

The one-class-to-rule-them-all is a bad idea, as it make the class unscalable and hard to test. The graph below shows the implementation of SolanaSDK at the moment:

SolanaSDK__(class)

Solution

The big class SolanaSDK has to be separated into multiple modules.

The term “independent” in this situation means:

  • The module can be initialized and used independently. For example:APIClient must needs only endpoint to be initialized and can be used independently without authorization.
  • The module has their own responsibility and doesn't need to know about another modules.

All modules has to be written in POP, which always starts with an interface (protocol). For example: class APIClient: SolanaAPIClient.

The SolanaSDK will be marked as deprecated for backward compatible.

The graph of SolanaSDK after refactoring is something like this:

SolanaSDK_-_after

Modules’ explaination:

  1. AccountStorage: SolanaAccountStorage stores user’s credentials and define if user is authorized.
  2. APIClient: SolanaAPIClient api client to connect with Solana RPC API, contains following methods (https://docs.solana.com/developing/clients/jsonrpc-api).
  3. TokensRepository: SolanaTokensRepository repository that provides informations about supported token in Solana blockchain. (https://raw.githubusercontent.com/solana-labs/token-list/main/src/tokens/solana.tokenlist.json)
  4. BlockchainClient: SolanaBlockchainClient the client that helps us preparing, signing and serializing transaction using SolanaPrograms before sending using method sendTransaction, simulateTransaction from SolanaAPIClient or forwarding to FeeRelayer.
  5. SolanaProgram Type of Programs that lives on Solana Blockchain that provides methods for preparing instructions in any transaction.
  6. TransactionParser: SolanaTransactionParser: Custom parser to define readable type of transaction, for example: Send, Swap, Receive,...
  7. Socket: SolanaSocket: Socket connection that provide suitable methods to observe user’s account or transaction signature status.

2. Highly depending on Rx libraries

Problem

The SolanaSwift library is right now deeply depending on RxSwift.

The SolanaSwift library is also depending on RxAlamofire for handling network request, it must be replaced by the native solution to reduce dependency.

Untitled

Solution

As swift concurrency is now backward compatible with iOS 13, we use async/await and URLSession as the replacement for RxSwift and RxAlamofire

Notice

In the scope of this refactoring, there would be no ui part touched, so a bridge needs to be created to convert async/await code to adapt new concurrency solution in UI (the UI will be refactored later).

3. Model is coupled inside namespace SolanaSDK

Problem

Model is coupled inside SolanaSDK

Solution

  • Move models outside of SolanaSDK, for example SolanaSDK.PublicKey becomes PublicKey
  • For backward compatibility, type alias has to be added back to SolanaSDK. For example:
extension SolanaSDK {
   typealias PublicKey = SolanaSwift.PublicKey // (?)
}

What is “neсessary”, and what is “nice to have”?

  1. The SolanaSDK is separated into multiple independent modules, which are located in separated folder. Еach module has to be fully tested.
  2. The SolanaSwift needs to be independent from RxSwift, RxAlamofire.
  3. The concurrency code is lightweight and easy to use.
  4. A bridge need to be built to keep the ui part unchanged (will be refactored later)

Task decomposition

This task has to be separated to child tasks, which equivalent to cleaning, deprecating and creating each modules in SolanaSDK:

  1. Group all deprecated implementation of SolanaSDK in to Deprecated folder, move all Models out of SolanaSDK, but don't break the old working solution.
  2. Implement AccountStorage: SolanaAccountStorage, blocked by 1
  3. Implement APIClient: SolanaAPIClient, blocked by 1
  4. Implement TokensRepository: SolanaTokensRepository, blocked by 1
  5. Implement BlockchainClient: SolanaBlockchainClient, blocked by 1
  6. Implement SolanaProgram , blocked by 1
  7. Implement TransactionParser: SolanaTransactionParser, blocked by 1
  8. Implement Socket: SolanaSocket, blocked by 1

Definition of done

  • RxSwift, RxAlamofire is removed from SolanaSwift’s dependencies, a bridge is created to map async function to return Observable to work with current Rx code in p2p-wallet-ios
  • Several modules in SolanaSDK are independent
  • All modules are fully tested

Can't send SPL transaction

So thats is my code

   private func transferSolanaToken(mnemonic: [String], wallet: HDWallet) {
    try async {
        let endpoint = APIEndPoint(
            address: "https://api.mainnet-beta.solana.com",
            network: .mainnetBeta
        )
        do {
            let account = try await Account(phrase: mnemonic, network: .mainnetBeta, derivablePath: .default)
            let blockchainClient = BlockchainClient(apiClient: JSONRPCAPIClient(endpoint: endpoint))
            let preparedTransaction = try await blockchainClient.prepareSendingSPLTokens(
                account: account,
                mintAddress: "cxxShYRVcepDudXhe7U62QHvw8uBJoKFifmzggGKVC2",  // USDC mint
                decimals: 6,
                from: "DnTwkxa6xtFB72w2t9PPrwuxksAR1Gb663UWTGLbVpYM", // Your usdc address
                to: "W3LJP23kwe4Vt6E2cpZ5DRHSNiJxfYwTxg8zuTmTKAT",
                amount: UInt64(1)
            )
            
            print(preparedTransaction)
            
            let result = try await blockchainClient.sendTransaction(preparedTransaction: 
      preparedTransaction.preparedTransaction)
            
            print(result)
        }
        catch {
            print("error")
        }
    }
 }

its fail at result line
where is my fail?
can i look some example of this transactions anywhere?
i try do like readme but it didn't work :c

[Migration] SolanaAPIClient

Base on their docs about getAccountInfo. The function should return nil if account doesn't exist.

Current implementation in our v2 version:

public func getAccountInfo<T: DecodableBufferLayout>(account: String) async throws -> BufferInfo<T> {
        let requestConfig = RequestConfiguration(encoding: "base64")
        let req = RequestEncoder.RequestType(method: "getAccountInfo", params: [account, requestConfig])
        let response: AnyResponse<Rpc<BufferInfo<T>>> = try await request(with: req)
        guard let ret = response.result?.value else {    // <- Wrong error catching!
            throw APIClientError.cantDecodeResponse
        }
        return ret
    }

Account imported from mnemonic is different from @solana/web3.js

With the same mnemonic: miracle pizza supply useful steak border same again youth silver access hundred
Solana swift output an account with public key: 3h1zGmCwsRJnVk5BuRNMLsPaQu1y2aqXqXDWYCgrp5UG
@solana/web3.js output an account with public key: HnXJX1Bvps8piQwDYEYC6oea9GEkvQvahvRj3c97X9xr

getSignaturesForAddress and getTransaction hardcoded for mainnet

I noticed that getSignaturesForAddress and getTransaction are both hardcoded to mainnet via an overridingEndpoint param. Is there a reason that we can't use testnet or devnet with these functions? In my build, I've just commented out the overridingEndpoint and it seems to work fine.

On a side note, I just started playing around with solana-swift and this is a great library so far....nice work!

example?

Hi! looks like a great project. I am not finding the Example directory on main was wondering if thats been omitted for a reason?

Would love to try it out.

getTokenAccountsByOwner did not provide tokenAmount

getTokenAccountsByOwner response is of type [TokenAccount<TokenAccountState>], but that does not have the token account balance amount.

The RPC method has a json example with the amounts. Tried with "jsonParsed" config but that will have decoding error.

Add one more signature to exist Transaction.

Hello everyone!
I get Transaction with signature from the backend and I need to add my own signature and sign transaction. So I will have two signature (first for paying fee, second is mine). But when I add my own signature I get error from Solana endpoint:

failed to send transaction: Transaction signature verification failure

I have created method for this (example from NodeJS) without overriding signature array:

public mutating func partialSign(signers: [Account]) throws {
            guard signers.count > 0 else { throw Error.invalidRequest(reason: "No signers") }
            
            // unique signers
            let signers = signers.reduce([Account](), { signers, signer in
                var uniqueSigners = signers
                if !uniqueSigners.contains(where: { $0.publicKey == signer.publicKey }) {
                    uniqueSigners.append(signer)
                }
                return uniqueSigners
            })
            
            // construct message
            let message = try compile()
            try partialSign(message: message, signers: signers)
        }

Does anybody can help me to add one more sign without error from Solana?

Codable support

Hey all, finding myself adding "Encoding" or "Decoding" support to most of the models. How come the library only supports one way and not Codable directly?

Thanks

Partial sign still doesn't work.

I try to sign transaction which I get from my server.

try transaction.partialSign(signers: [account])
let data = try transaction.serialize()

The problem is in the order of accounts keys (according to instructions in transaction message) and signatures order.

Signed keys:

[
7qNz8fjLwsTF3ifPd8FUZt28PUr5KV593X7XBV2x2ojV,
DkLZoyq5xs92M92yWY2Xrzj4nTFPvx1c1oyfsA6TMPCz,
98P3VqKQ5kRb3Mowp4DPZepEUCQhYpuo9r46sEhSYvW2
]

Signatures:

[
SolanaSwift.Transaction.Signature(signature: Optional(64 bytes), publicKey: 7qNz8fjLwsTF3ifPd8FUZt28PUr5KV593X7XBV2x2ojV),
SolanaSwift.Transaction.Signature(signature: nil, publicKey: 98P3VqKQ5kRb3Mowp4DPZepEUCQhYpuo9r46sEhSYvW2),
SolanaSwift.Transaction.Signature(signature: Optional(64 bytes), publicKey: DkLZoyq5xs92M92yWY2Xrzj4nTFPvx1c1oyfsA6TMPCz)
]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.