Skip to content

Commit

Permalink
up
Browse files Browse the repository at this point in the history
  • Loading branch information
nerzh committed Nov 18, 2021
1 parent 12e7aee commit 3d24853
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Swift Client for Free Ton SDK

[![SPM](https://img.shields.io/badge/swift-package%20manager-green)](https://swift.org/package-manager/)
[![SPM](https://img.shields.io/badge/SDK%20VERSION-1.23.0-orange)](https://github.com/tonlabs/TON-SDK)
[![SPM](https://img.shields.io/badge/SDK%20VERSION-1.25.0-orange)](https://github.com/tonlabs/TON-SDK)

Swift is a strongly typed language that has long been used not only for iOS development. Apple is actively promoting it to new platforms and today it can be used for almost any task. Thanks to this, this implementation provides the work of TonSDK on many platforms at once, including the native one for mobile phones. Let me remind you that swift can also be built for android.

Expand Down
20 changes: 18 additions & 2 deletions Sources/TonClientSwift/Abi/Abi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ public final class TSDKAbiModule {

/// Decodes account data using provided data BOC and ABI.
/// Note: this feature requires ABI 2.1 or higher.
public func decode_account_data(_ payload: TSDKParamsOfDecodeAccountData, _ handler: @escaping (TSDKBindingResponse<TSDKResultOfDecodeData, TSDKClientError>) throws -> Void
public func decode_account_data(_ payload: TSDKParamsOfDecodeAccountData, _ handler: @escaping (TSDKBindingResponse<TSDKResultOfDecodeAccountData, TSDKClientError>) throws -> Void
) {
let method: String = "decode_account_data"
binding.requestLibraryAsync(methodName(module, method), payload) { (requestId, params, responseType, finished) in
var response: TSDKBindingResponse<TSDKResultOfDecodeData, TSDKClientError> = .init()
var response: TSDKBindingResponse<TSDKResultOfDecodeAccountData, TSDKClientError> = .init()
response.update(requestId, params, responseType, finished)
try handler(response)
}
Expand Down Expand Up @@ -154,4 +154,20 @@ public final class TSDKAbiModule {
}
}

/// Decodes BOC into JSON as a set of provided parameters.
/// Solidity functions use ABI types for [builder encoding](https://github.com/tonlabs/TON-Solidity-Compiler/blob/master/API.md#tvmbuilderstore).
/// The simplest way to decode such a BOC is to use ABI decoding.
/// ABI has it own rules for fields layout in cells so manually encodedBOC can not be described in terms of ABI rules.
/// To solve this problem we introduce a new ABI type `Ref(<ParamType>)`which allows to store `ParamType` ABI parameter in cell reference and, thus,decode manually encoded BOCs. This type is available only in `decode_boc` functionand will not be available in ABI messages encoding until it is included into some ABI revision.
/// Such BOC descriptions covers most users needs. If someone wants to decode some BOC whichcan not be described by these rules (i.e. BOC with TLB containing constructors of flagsdefining some parsing conditions) then they can decode the fields up to fork condition,check the parsed data manually, expand the parsing schema and then decode the whole BOCwith the full schema.
public func decode_boc(_ payload: TSDKParamsOfDecodeBoc, _ handler: @escaping (TSDKBindingResponse<TSDKResultOfDecodeBoc, TSDKClientError>) throws -> Void
) {
let method: String = "decode_boc"
binding.requestLibraryAsync(methodName(module, method), payload) { (requestId, params, responseType, finished) in
var response: TSDKBindingResponse<TSDKResultOfDecodeBoc, TSDKClientError> = .init()
response.update(requestId, params, responseType, finished)
try handler(response)
}
}

}
25 changes: 24 additions & 1 deletion Sources/TonClientSwift/Abi/AbiTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ public struct TSDKParamsOfDecodeAccountData: Codable {
}
}

public struct TSDKResultOfDecodeData: Codable {
public struct TSDKResultOfDecodeAccountData: Codable {
/// Decoded data as a JSON structure.
public var data: AnyValue

Expand Down Expand Up @@ -612,3 +612,26 @@ public struct TSDKResultOfDecodeInitialData: Codable {
}
}

public struct TSDKParamsOfDecodeBoc: Codable {
/// Parameters to decode from BOC
public var params: [TSDKAbiParam]
/// Data BOC or BOC handle
public var boc: String
public var allow_partial: Bool

public init(params: [TSDKAbiParam], boc: String, allow_partial: Bool) {
self.params = params
self.boc = boc
self.allow_partial = allow_partial
}
}

public struct TSDKResultOfDecodeBoc: Codable {
/// Decoded data as a JSON structure.
public var data: AnyValue

public init(data: AnyValue) {
self.data = data
}
}

11 changes: 11 additions & 0 deletions Sources/TonClientSwift/Boc/Boc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ public final class TSDKBocModule {
}
}

/// Calculates BOC depth
public func get_boc_depth(_ payload: TSDKParamsOfGetBocDepth, _ handler: @escaping (TSDKBindingResponse<TSDKResultOfGetBocDepth, TSDKClientError>) throws -> Void
) {
let method: String = "get_boc_depth"
binding.requestLibraryAsync(methodName(module, method), payload) { (requestId, params, responseType, finished) in
var response: TSDKBindingResponse<TSDKResultOfGetBocDepth, TSDKClientError> = .init()
response.update(requestId, params, responseType, finished)
try handler(response)
}
}

/// Extracts code from TVC contract image
public func get_code_from_tvc(_ payload: TSDKParamsOfGetCodeFromTvc, _ handler: @escaping (TSDKBindingResponse<TSDKResultOfGetCodeFromTvc, TSDKClientError>) throws -> Void
) {
Expand Down
37 changes: 35 additions & 2 deletions Sources/TonClientSwift/Boc/BocTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public struct TSDKResultOfGetBlockchainConfig: Codable {
}

public struct TSDKParamsOfGetBocHash: Codable {
/// BOC encoded as base64
/// BOC encoded as base64 or BOC handle
public var boc: String

public init(boc: String) {
Expand All @@ -99,6 +99,24 @@ public struct TSDKResultOfGetBocHash: Codable {
}
}

public struct TSDKParamsOfGetBocDepth: Codable {
/// BOC encoded as base64 or BOC handle
public var boc: String

public init(boc: String) {
self.boc = boc
}
}

public struct TSDKResultOfGetBocDepth: Codable {
/// BOC root cell depth
public var depth: UInt32

public init(depth: UInt32) {
self.depth = depth
}
}

public struct TSDKParamsOfGetCodeFromTvc: Codable {
/// Contract TVC image or image BOC handle
public var tvc: String
Expand Down Expand Up @@ -277,8 +295,16 @@ public struct TSDKParamsOfDecodeTvc: Codable {
public struct TSDKResultOfDecodeTvc: Codable {
/// Contract code BOC encoded as base64 or BOC handle
public var code: String?
/// Contract code hash
public var code_hash: String?
/// Contract code depth
public var code_depth: UInt32?
/// Contract data BOC encoded as base64 or BOC handle
public var data: String?
/// Contract data hash
public var data_hash: String?
/// Contract data depth
public var data_depth: UInt32?
/// Contract library BOC encoded as base64 or BOC handle
public var library: String?
/// `special.tick` field.
Expand All @@ -289,14 +315,21 @@ public struct TSDKResultOfDecodeTvc: Codable {
public var tock: Bool?
/// Is present and non-zero only in instances of large smart contracts
public var split_depth: UInt32?
/// Compiler version, for example 'sol 0.49.0'
public var compiler_version: String?

public init(code: String? = nil, data: String? = nil, library: String? = nil, tick: Bool? = nil, tock: Bool? = nil, split_depth: UInt32? = nil) {
public init(code: String? = nil, code_hash: String? = nil, code_depth: UInt32? = nil, data: String? = nil, data_hash: String? = nil, data_depth: UInt32? = nil, library: String? = nil, tick: Bool? = nil, tock: Bool? = nil, split_depth: UInt32? = nil, compiler_version: String? = nil) {
self.code = code
self.code_hash = code_hash
self.code_depth = code_depth
self.data = data
self.data_hash = data_hash
self.data_depth = data_depth
self.library = library
self.tick = tick
self.tock = tock
self.split_depth = split_depth
self.compiler_version = compiler_version
}
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/TonClientSwift/Client/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public final class TSDKClientModule {
public var tvm: TSDKTvmModule
public var net: TSDKNetModule
public var debot: TSDKDebotModule
public var proofs: TSDKProofsModule

public init(config: TSDKClientConfig) throws {
self.config = config
Expand All @@ -23,6 +24,7 @@ public final class TSDKClientModule {
self.tvm = TSDKTvmModule(binding: binding)
self.net = TSDKNetModule(binding: binding)
self.debot = TSDKDebotModule(binding: binding)
self.proofs = TSDKProofsModule(binding: binding)
}

/// Returns Core Library API reference
Expand Down
20 changes: 18 additions & 2 deletions Sources/TonClientSwift/Client/ClientTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public enum TSDKClientErrorCode: Int, Codable {
case CanNotParseNumber = 32
case InternalError = 33
case InvalidHandle = 34
case LocalStorageError = 35
}

public enum TSDKAppRequestResultEnumTypes: String, Codable {
Expand All @@ -57,12 +58,17 @@ public struct TSDKClientConfig: Codable {
public var crypto: TSDKCryptoConfig?
public var abi: TSDKAbiConfig?
public var boc: TSDKBocConfig?
public var proofs: TSDKProofsConfig?
/// For file based storage is a folder name where SDK will store its data. For browser based is a browser async storage key prefix. Default (recommended) value is "~/.tonclient" for native environments and ".tonclient" for web-browser.
public var local_storage_path: String?

public init(network: TSDKNetworkConfig? = nil, crypto: TSDKCryptoConfig? = nil, abi: TSDKAbiConfig? = nil, boc: TSDKBocConfig? = nil) {
public init(network: TSDKNetworkConfig? = nil, crypto: TSDKCryptoConfig? = nil, abi: TSDKAbiConfig? = nil, boc: TSDKBocConfig? = nil, proofs: TSDKProofsConfig? = nil, local_storage_path: String? = nil) {
self.network = network
self.crypto = crypto
self.abi = abi
self.boc = boc
self.proofs = proofs
self.local_storage_path = local_storage_path
}
}

Expand Down Expand Up @@ -101,7 +107,7 @@ public struct TSDKNetworkConfig: Codable {
/// If the latency (time-lag) is less then `NetworkConfig.max_latency`then library selects another endpoint.
/// Must be specified in milliseconds. Default is 60000 (1 min).
public var latency_detection_interval: UInt32?
/// Maximum value for the endpoint's blockchain data syncronization latency (time-lag). Library periodically checks the current endpoint for blockchain data syncronization latency. If the latency (time-lag) is less then `NetworkConfig.max_latency` then library selects another endpoint.
/// Maximum value for the endpoint's blockchain data syncronization latency (time-lag). Library periodically checks the current endpoint for blockchain data synchronization latency. If the latency (time-lag) is less then `NetworkConfig.max_latency` then library selects another endpoint.
/// Must be specified in milliseconds. Default is 60000 (1 min).
public var max_latency: UInt32?
/// Default timeout for http requests.
Expand Down Expand Up @@ -170,6 +176,16 @@ public struct TSDKBocConfig: Codable {
}
}

public struct TSDKProofsConfig: Codable {
/// Cache proofs in the local storage.
/// Default is `true`. If this value is set to `true`, downloaded proofs and master-chain BOCs are saved into thepersistent local storage (e.g. file system for native environments or browser's IndexedDBfor the web); otherwise all the data is cached only in memory in current client's contextand will be lost after destruction of the client.
public var cache_in_local_storage: Bool?

public init(cache_in_local_storage: Bool? = nil) {
self.cache_in_local_storage = cache_in_local_storage
}
}

public struct TSDKBuildInfoDependency: Codable {
/// Dependency name.
/// Usually it is a crate name.
Expand Down
54 changes: 54 additions & 0 deletions Sources/TonClientSwift/Proofs/Proofs.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
public final class TSDKProofsModule {

private var binding: TSDKBindingModule
public let module: String = "proofs"

public init(binding: TSDKBindingModule) {
self.binding = binding
}

/// Proves that a given block's data, which is queried from TONOS API, can be trusted.
/// This function checks block proofs and compares given data with the proven.
/// If the given data differs from the proven, the exception will be thrown.
/// The input param is a single block's JSON object, which was queried from DApp server usingfunctions such as `net.query`, `net.query_collection` or `net.wait_for_collection`.
/// If block's BOC is not provided in the JSON, it will be queried from DApp server(in this case it is required to provide at least `id` of block).
/// Please note, that joins (like `signatures` in `Block`) are separated entities and not supported,so function will throw an exception in a case if JSON being checked has such entities in it.
/// If `cache_in_local_storage` in config is set to `true` (default), downloaded proofs andmaster-chain BOCs are saved into the persistent local storage (e.g. file system for nativeenvironments or browser's IndexedDB for the web); otherwise all the data is cached only inmemory in current client's context and will be lost after destruction of the client.
/// **Why Proofs are needed**Proofs are needed to ensure that the data downloaded from a DApp server is real blockchaindata. Checking proofs can protect from the malicious DApp server which can potentially providefake data, or also from "Man in the Middle" attacks class.
/// **What Proofs are**Simply, proof is a list of signatures of validators', which have signed this particular master-block.
/// The very first validator set's public keys are included in the zero-state. Whe know a root hashof the zero-state, because it is stored in the network configuration file, it is our authorityroot. For proving zero-state it is enough to calculate and compare its root hash.
/// In each new validator cycle the validator set is changed. The new one is stored in a key-block,which is signed by the validator set, which we already trust, the next validator set will bestored to the new key-block and signed by the current validator set, and so on.
/// In order to prove any block in the master-chain we need to check, that it has been signed bya trusted validator set. So we need to check all key-blocks' proofs, started from the zero-stateand until the block, which we want to prove. But it can take a lot of time and traffic todownload and prove all key-blocks on a client. For solving this, special trusted blocks are usedin TON-SDK.
/// The trusted block is the authority root, as well, as the zero-state. Each trusted block is the`id` (e.g. `root_hash`) of the already proven key-block. There can be plenty of trustedblocks, so there can be a lot of authority roots. The hashes of trusted blocks for MainNetand DevNet are hardcoded in SDK in a separated binary file (trusted_key_blocks.bin) and canbe updated for each release.
/// In future SDK releases, one will also be able to provide their hashes of trusted blocks forother networks, besides for MainNet and DevNet.
/// By using trusted key-blocks, in order to prove any block, we can prove chain of key-blocks tothe closest previous trusted key-block, not only to the zero-state.
/// But shard-blocks don't have proofs on DApp server. In this case, in order to prove any shard-block data, we search for a corresponding master-block, which contains the root hash of thisshard-block, or some shard block which is linked to that block in shard-chain. After provingthis master-block, we traverse through each link and calculate and compare hashes with links,one-by-one. After that we can ensure that this shard-block has also been proven.
public func proof_block_data(_ payload: TSDKParamsOfProofBlockData, _ handler: @escaping (TSDKBindingResponse<TSDKNoneResult, TSDKClientError>) throws -> Void
) {
let method: String = "proof_block_data"
binding.requestLibraryAsync(methodName(module, method), payload) { (requestId, params, responseType, finished) in
var response: TSDKBindingResponse<TSDKNoneResult, TSDKClientError> = .init()
response.update(requestId, params, responseType, finished)
try handler(response)
}
}

/// Proves that a given transaction's data, which is queried from TONOS API, can be trusted.
/// This function requests the corresponding block, checks block proofs, ensures that given transactionexists in the proven block and compares given data with the proven.
/// If the given data differs from the proven, the exception will be thrown.
/// The input parameter is a single transaction's JSON object (see params description),which was queried from TONOS API using functions such as `net.query`, `net.query_collection`or `net.wait_for_collection`.
/// If transaction's BOC and/or `block_id` are not provided in the JSON, they will be queried fromTONOS API (in this case it is required to provide at least `id` of transaction).
/// Please note, that joins (like `account`, `in_message`, `out_messages`, etc. in `Transaction`entity) are separated entities and not supported, so function will throw an exception in a caseif JSON being checked has such entities in it.
/// If `cache_in_local_storage` in config is set to `true` (default), downloaded proofs andmaster-chain BOCs are saved into the persistent local storage (e.g. file system for nativeenvironments or browser's IndexedDB for the web); otherwise all the data is cached only inmemory in current client's context and will be lost after destruction of the client.
/// For more information about proofs checking, see description of `proof_block_data` function.
public func proof_transaction_data(_ payload: TSDKParamsOfProofTransactionData, _ handler: @escaping (TSDKBindingResponse<TSDKNoneResult, TSDKClientError>) throws -> Void
) {
let method: String = "proof_transaction_data"
binding.requestLibraryAsync(methodName(module, method), payload) { (requestId, params, responseType, finished) in
var response: TSDKBindingResponse<TSDKNoneResult, TSDKClientError> = .init()
response.update(requestId, params, responseType, finished)
try handler(response)
}
}

}
25 changes: 25 additions & 0 deletions Sources/TonClientSwift/Proofs/ProofsTypes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
public enum TSDKProofsErrorCode: Int, Codable {
case InvalidData = 901
case ProofCheckFailed = 902
case InternalError = 903
case DataDiffersFromProven = 904
}

public struct TSDKParamsOfProofBlockData: Codable {
/// Single block's data, retrieved from TONOS API, that needs proof. Required fields are `id` and/or top-level `boc` (for block identification), others are optional.
public var block: AnyValue

public init(block: AnyValue) {
self.block = block
}
}

public struct TSDKParamsOfProofTransactionData: Codable {
/// Single transaction's data as queried from DApp server, without modifications. The required fields are `id` and/or top-level `boc`, others are optional. In order to reduce network requests count, it is recommended to provide `block_id` and `boc` of transaction.
public var transaction: AnyValue

public init(transaction: AnyValue) {
self.transaction = transaction
}
}

0 comments on commit 3d24853

Please sign in to comment.