Merge pull request #36 from zeriontech/feature/solana

Feature/solana
This commit is contained in:
Ivan Grachev 2022-05-04 02:00:16 +03:00 committed by GitHub
commit 4294e6b65a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 907 additions and 74 deletions

View File

@ -6,12 +6,36 @@ extension SafariRequest {
struct Solana: SafariRequestBody {
enum Method: String, Decodable, CaseIterable {
case connect, signMessage, signTransaction, signAllTransactions, signAndSendTransaction
}
let method: Method
let publicKey: String
let message: String?
let messages: [String]?
let displayHex: Bool
let sendOptions: [String: Any]?
init?(name: String, json: [String: Any]) {
guard let method = Method(rawValue: name),
let publicKey = json["publicKey"] as? String else { return nil }
self.method = method
self.publicKey = publicKey
let parameters = (json["object"] as? [String: Any])?["params"] as? [String: Any]
self.message = parameters?["message"] as? String
self.messages = parameters?["messages"] as? [String]
self.displayHex = (parameters?["display"] as? String) == "hex"
self.sendOptions = parameters?["options"] as? [String: Any]
}
var responseUpdatesStoredConfiguration: Bool {
return false
switch method {
case .connect:
return true
case .signMessage, .signTransaction, .signAllTransactions, .signAndSendTransaction:
return false
}
}
}

View File

@ -6,6 +6,16 @@ extension ResponseToExtension {
struct Solana: Codable {
let publicKey: String?
let result: String?
let results: [String]?
init(publicKey: String? = nil, result: String? = nil, results: [String]? = nil) {
self.publicKey = publicKey
self.result = result
self.results = results
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -13,14 +13,20 @@ window.tokenary.postMessage = (name, id, body, provider) => {
};
window.ethereum = new TokenaryEthereum();
const handler = {
const ethereumHandler = {
get(target, property) {
return window.ethereum;
}
}
window.web3 = new Proxy(window.ethereum, handler);
window.web3 = new Proxy(window.ethereum, ethereumHandler);
window.solana = new TokenarySolana();
const solanaHandler = {
get(target, property) {
return window.solana;
}
}
window.phantom = new Proxy(window.solana, solanaHandler);
window.addEventListener("message", function(event) {
if (event.source == window && event.data && event.data.direction == "from-content-script") {

View File

@ -15,6 +15,7 @@
"author": "Tokenary <support@tokenary.io>",
"license": "MIT",
"dependencies": {
"bs58": "^5.0.0",
"buffer": "^5.6.0",
"events": "^3.2.0",
"isutf8": "^3.1.1"

View File

@ -2,19 +2,234 @@
"use strict";
import RPCServer from "./rpc";
import ProviderRpcError from "./error";
import Utils from "./utils";
import IdMapping from "./id_mapping";
import { EventEmitter } from "events";
import isUtf8 from "isutf8";
import { PublicKey, Transaction } from "@solana/web3.js";
import bs58 from "bs58";
class TokenarySolana extends EventEmitter {
constructor() {
super();
processTokenaryResponse(id, response) {
this.idMapping = new IdMapping();
this.callbacks = new Map();
this.respondWithBuffer = new Map();
this.transactionsPendingSignature = new Map();
this.isPhantom = true;
this.publicKey = null;
this.isConnected = false;
this.isTokenary = true;
this.didGetLatestConfiguration = false;
this.pendingPayloads = [];
}
connect() {
return this.request({method: "connect"});
}
disconnect() {
// TODO: implement
// support also via request "disconnect" method
}
// provider.on("accountChanged", (publicKey: PublicKey | null));
// TODO: support emitting accountChanged (on switch account event)
signTransaction(transaction) {
const params = {message: bs58.encode(transaction.serializeMessage())};
const payload = {method: "signTransaction", params: params, id: Utils.genId()};
this.transactionsPendingSignature.set(payload.id, [transaction]);
return this.request(payload);
}
signAllTransactions(transactions) {
const messages = transactions.map(transaction => {
return bs58.encode(transaction.serializeMessage());
});
const params = {messages: messages};
const payload = {method: "signAllTransactions", params: params, id: Utils.genId()};
this.transactionsPendingSignature.set(payload.id, transactions);
return this.request(payload);
}
signAndSendTransaction(transaction, options) {
var params = {message: bs58.encode(transaction.serializeMessage())};
if (typeof options !== "undefined") {
params.options = options;
}
return this.request({method: "signAndSendTransaction", params: params});
}
signMessage(encodedMessage, display) {
var params = {message: encodedMessage};
if (typeof display !== "undefined") {
params.display = display;
}
const payload = {method: "signMessage", params: params, id: Utils.genId()};
this.respondWithBuffer.set(payload.id, true);
return this.request(payload);
}
request(payload) {
this.idMapping.tryIntifyId(payload);
return new Promise((resolve, reject) => {
if (!payload.id) {
payload.id = Utils.genId();
}
this.callbacks.set(payload.id, (error, data) => {
// Some dapps do not get responses sent without a delay.
// e.g., nftx.io does not start with a latest account if response is sent without a delay.
setTimeout( function() {
if (error) {
reject(error);
} else {
resolve(data);
}
}, 1);
});
switch (payload.method) {
case "connect":
case "signMessage":
case "signTransaction":
case "signAllTransactions":
case "signAndSendTransaction":
return this.processPayload(payload);
default:
this.callbacks.delete(payload.id);
return;
}
});
}
processPayload(payload) {
if (!this.didGetLatestConfiguration) {
this.pendingPayloads.push(payload);
return;
}
switch (payload.method) {
case "connect":
if (!this.publicKey) {
return this.postMessage("connect", payload.id, {});
} else {
this.isConnected = true;
this.emitConnect(this.publicKey);
return this.sendResponse(payload.id, {publicKey: this.publicKey});
}
case "signMessage":
if (typeof payload.params.message !== "string") {
payload.params.message = Utils.bufferToHex(payload.params.message);
}
return this.postMessage("signMessage", payload.id, payload);
case "signTransaction":
return this.postMessage("signTransaction", payload.id, payload);
case "signAllTransactions":
return this.postMessage("signAllTransactions", payload.id, payload);
case "signAndSendTransaction":
return this.postMessage("signAndSendTransaction", payload.id, payload);
}
}
emitConnect(publicKey) {
this.emit("connect", publicKey);
}
processTokenaryResponse(id, response) {
if (response.name == "didLoadLatestConfiguration") {
this.didGetLatestConfiguration = true;
if ("publicKey" in response) {
const publicKey = new PublicKey(response.publicKey);
this.publicKey = publicKey;
}
for(let payload of this.pendingPayloads) {
this.processPayload(payload);
}
this.pendingPayloads = [];
} else if ("publicKey" in response) {
this.isConnected = true;
const publicKey = new PublicKey(response.publicKey);
this.publicKey = publicKey;
this.sendResponse(id, {publicKey: publicKey});
this.emitConnect(publicKey);
} else if ("result" in response) {
if (response.name == "signTransaction" || response.name == "signAndSendTransaction") {
if (this.transactionsPendingSignature.has(id)) {
const pending = this.transactionsPendingSignature.get(id);
this.transactionsPendingSignature.delete(id);
const buffer = Utils.messageToBuffer(bs58.decode(response.result));
const transaction = pending[0];
transaction.addSignature(this.publicKey, buffer);
this.sendResponse(id, transaction);
} else {
this.sendResponse(id, {signature: response.result, publicKey: this.publicKey.toString()});
}
} else {
if (this.respondWithBuffer.get(id) === true) {
this.respondWithBuffer.delete(id);
const buffer = Utils.messageToBuffer(bs58.decode(response.result));
this.sendResponse(id, {signature: buffer, publicKey: this.publicKey});
} else {
this.sendResponse(id, {signature: response.result, publicKey: this.publicKey.toString()});
}
}
} else if ("results" in response) {
if (this.transactionsPendingSignature.has(id)) {
const transactions = this.transactionsPendingSignature.get(id);
this.transactionsPendingSignature.delete(id);
response.results.forEach( (signature, index) => {
const buffer = Utils.messageToBuffer(bs58.decode(signature));
transactions[index].addSignature(this.publicKey, buffer);
});
this.sendResponse(id, transactions);
} else {
this.sendResponse(id, {signatures: response.results, publicKey: this.publicKey.toString()});
}
} else if ("error" in response) {
this.respondWithBuffer.delete(id);
this.transactionsPendingSignature.delete(id);
this.sendError(id, response.error);
}
}
postMessage(handler, id, data) {
var publicKey = "";
if (this.publicKey) {
publicKey = this.publicKey.toString();
}
let object = {
object: data,
publicKey: publicKey,
};
window.tokenary.postMessage(handler, id, object, "solana");
}
sendResponse(id, result) {
let originId = this.idMapping.tryPopId(id) || id;
let callback = this.callbacks.get(id);
if (callback) {
callback(null, result);
this.callbacks.delete(id);
} else {
console.log(`callback id: ${id} not found`);
}
}
sendError(id, error) {
console.log(`<== ${id} sendError ${error}`);
let callback = this.callbacks.get(id);
if (callback) {
callback(error instanceof Error ? error : new Error(error), null);
this.callbacks.delete(id);
}
}
}
module.exports = TokenarySolana;

View File

@ -1771,6 +1771,11 @@ base-x@^3.0.2:
dependencies:
safe-buffer "^5.0.1"
base-x@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a"
integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==
base64-js@^1.0.2, base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@ -1959,6 +1964,13 @@ bs58@^4.0.0:
dependencies:
base-x "^3.0.2"
bs58@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-5.0.0.tgz#865575b4d13c09ea2a84622df6c8cbeb54ffc279"
integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==
dependencies:
base-x "^4.0.0"
bs58check@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"

View File

@ -4,6 +4,7 @@ enum ApprovalSubject {
case signMessage
case signPersonalMessage
case signTypedData
case approveTransaction
var asAuthenticationReason: AuthenticationReason {
switch self {
@ -13,6 +14,8 @@ enum ApprovalSubject {
return .signPersonalMessage
case .signTypedData:
return .signTypedData
case .approveTransaction:
return .approveTransaction
}
}
@ -24,6 +27,8 @@ enum ApprovalSubject {
return Strings.signPersonalMessage
case .signTypedData:
return Strings.signTypedData
case .approveTransaction:
return Strings.approveTransaction
}
}
}

View File

@ -9,6 +9,7 @@ enum AuthenticationReason {
case signMessage
case signPersonalMessage
case signTypedData
case approveTransaction
var title: String {
switch self {
@ -28,6 +29,8 @@ enum AuthenticationReason {
return Strings.signPersonalMessage
case .signTypedData:
return Strings.signTypedData
case .approveTransaction:
return Strings.approveTransaction
}
}
}

View File

@ -6,6 +6,7 @@ struct DappRequestProcessor {
private static let walletsManager = WalletsManager.shared
private static let ethereum = Ethereum.shared
private static let solana = Solana.shared
static func processSafariRequest(_ request: SafariRequest, completion: @escaping () -> Void) -> DappRequestAction {
guard ExtensionBridge.hasRequest(id: request.id) else {
@ -16,6 +17,11 @@ struct DappRequestProcessor {
switch request.body {
case let .ethereum(body):
return process(request: request, ethereumRequest: body, completion: completion)
case let .solana(body):
return process(request: request, solanaRequest: body, completion: completion)
case .tezos:
respond(to: request, error: "Tezos is not supported yet", completion: completion)
return .none
case let .unknown(body):
switch body.method {
case .justShowApp:
@ -34,12 +40,80 @@ struct DappRequestProcessor {
}
return .selectAccount(action)
}
case .solana:
respond(to: request, error: "Solana is not supported yet", completion: completion)
case .tezos:
respond(to: request, error: "Tezos is not supported yet", completion: completion)
}
return .none
}
private static func process(request: SafariRequest, solanaRequest body: SafariRequest.Solana, completion: @escaping () -> Void) -> DappRequestAction {
let peerMeta = PeerMeta(title: request.host, iconURLString: request.favicon)
switch body.method {
case .connect:
// TODO: pick an address from the list
let responseBody = ResponseToExtension.Solana(publicKey: "")
respond(to: request, body: .solana(responseBody), completion: completion)
return .none // TODO: replace with .selectAccount
case .signAllTransactions:
guard let messages = body.messages else {
respond(to: request, error: Strings.somethingWentWrong, completion: completion)
return .none
}
let displayMessage = messages.joined(separator: "\n\n")
let action = SignMessageAction(provider: request.provider, subject: .approveTransaction, address: body.publicKey, meta: displayMessage, peerMeta: peerMeta) { approved in
if approved {
var results = [String]()
for message in messages {
guard let signed = solana.sign(message: message, asHex: false) else {
respond(to: request, error: Strings.failedToSign, completion: completion)
return
}
results.append(signed)
}
let responseBody = ResponseToExtension.Solana(results: results)
respond(to: request, body: .solana(responseBody), completion: completion)
} else {
respond(to: request, error: Strings.failedToSign, completion: completion)
}
}
return .approveMessage(action)
case .signMessage, .signTransaction, .signAndSendTransaction:
guard let message = body.message else {
respond(to: request, error: Strings.somethingWentWrong, completion: completion)
return .none
}
let displayMessage: String
let subject: ApprovalSubject
switch body.method {
case .signMessage:
displayMessage = body.displayHex ? message : (String(data: Data(hex: message), encoding: .utf8) ?? message)
subject = .signMessage
default:
displayMessage = message
subject = .approveTransaction
}
let action = SignMessageAction(provider: request.provider, subject: subject, address: body.publicKey, meta: displayMessage, peerMeta: peerMeta) { approved in
guard approved else {
respond(to: request, error: Strings.failedToSign, completion: completion)
return
}
if body.method == .signAndSendTransaction {
solana.signAndSendTransaction(message: message, options: body.sendOptions) { result in
switch result {
case let .success(signature):
let responseBody = ResponseToExtension.Solana(result: signature)
respond(to: request, body: .solana(responseBody), completion: completion)
case .failure:
respond(to: request, error: Strings.failedToSend, completion: completion)
}
}
} else if let signed = solana.sign(message: message, asHex: body.method == .signMessage) {
let responseBody = ResponseToExtension.Solana(result: signed)
respond(to: request, body: .solana(responseBody), completion: completion)
} else {
respond(to: request, error: Strings.failedToSign, completion: completion)
}
}
return .approveMessage(action)
}
}
private static func process(request: SafariRequest, ethereumRequest: SafariRequest.Ethereum, completion: @escaping () -> Void) -> DappRequestAction {

View File

@ -0,0 +1,290 @@
// Copyright © 2022 Tokenary. All rights reserved.
import Foundation
import WalletCore
class Solana {
enum SendTransactionError: Error {
case blockhashNotFound, unknown
}
private enum Method: String {
case sendTransaction, simulateTransaction, getLatestBlockhash
}
private struct SendTransactionResponse: Codable {
let result: String?
private let error: Error?
var blockhashNotFound: Bool {
return error?.data.err == "BlockhashNotFound"
}
private struct Error: Codable {
let data: Data
struct Data: Codable {
let err: String
}
}
}
private struct LatestBlockhashResponse: Codable {
let result: Result
struct Result: Codable {
let value: Value
struct Value: Codable {
let blockhash: String
}
}
}
static let shared = Solana()
private let urlSession = URLSession(configuration: .default)
private let rpcURL = URL(string: "https://api.mainnet-beta.solana.com")!
private init() {}
func sign(message: String, asHex: Bool) -> String? {
let digest = asHex ? Data(hex: message) : Base58.decodeNoCheck(string: message)
guard let digest = digest else { return nil }
let words = ""
let password = ""
guard let key = StoredKey.importHDWallet(mnemonic: words, name: "", password: Data(password.utf8), coin: .solana),
let phantomPrivateKey = key.wallet(password: Data(password.utf8))?.getKey(coin: .solana, derivationPath: "m/44'/501'/0'/0'") else { return nil }
if let data = phantomPrivateKey.sign(digest: digest, curve: CoinType.solana.curve) {
return Base58.encodeNoCheck(data: data)
} else {
return nil
}
}
func signAndSendTransaction(retryCount: Int = 0, message: String, options: [String: Any]?, completion: @escaping (Result<String, SendTransactionError>) -> Void) {
guard retryCount < 3,
let signed = sign(message: message, asHex: false),
let raw = compileTransactionData(message: message, signature: signed, simulation: false) else {
completion(.failure(.unknown))
return
}
sendTransaction(signed: raw, options: options) { [weak self] result in
switch result {
case let .success(result):
completion(.success(result))
case let .failure(sendTransactionError):
switch sendTransactionError {
case .unknown:
completion(.failure(.unknown))
case .blockhashNotFound:
self?.updateBlockhash(message: message) { updatedMessage in
if let updatedMessage = updatedMessage {
self?.signAndSendTransaction(retryCount: retryCount + 1, message: updatedMessage, options: options, completion: completion)
} else {
completion(.failure(.unknown))
}
}
}
}
}
}
// MARK: - Private
private func createRequest(method: Method, parameters: [Any]? = nil) -> URLRequest {
var request = URLRequest(url: rpcURL)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
var dict: [String: Any] = [
"method": method.rawValue,
"id": 1,
"jsonrpc": "2.0"
]
if let parameters = parameters {
dict["params"] = parameters
}
request.httpBody = try? JSONSerialization.data(withJSONObject: dict, options: .fragmentsAllowed)
return request
}
private func getLatestBlockhash(completion: @escaping (String?) -> Void) {
let request = createRequest(method: .getLatestBlockhash)
let dataTask = urlSession.dataTask(with: request) { data, _, _ in
DispatchQueue.main.async {
if let data = data,
let response = try? JSONDecoder().decode(LatestBlockhashResponse.self, from: data) {
completion(response.result.value.blockhash)
} else {
completion(nil)
}
}
}
dataTask.resume()
}
private func sendTransaction(signed: String, options: [String: Any]?, completion: @escaping (Result<String, SendTransactionError>) -> Void) {
var parameters: [Any] = [signed]
if let options = options {
parameters.append(options)
}
let request = createRequest(method: .sendTransaction, parameters: parameters)
let dataTask = urlSession.dataTask(with: request) { data, _, _ in
DispatchQueue.main.async {
if let data = data,
let response = try? JSONDecoder().decode(SendTransactionResponse.self, from: data) {
if let result = response.result {
completion(.success(result))
} else {
completion(.failure(response.blockhashNotFound ? .blockhashNotFound : .unknown))
}
} else {
completion(.failure(.unknown))
}
}
}
dataTask.resume()
}
private func simulateTransaction(serializedMessage: String, signature: String, publicKey: String, completion: @escaping (Any?) -> Void) {
guard let message = compileTransactionData(message: serializedMessage, signature: signature, simulation: true) else {
completion(nil)
return
}
let configuration: [String: Any] = ["accounts": ["encoding": "jsonParsed", "addresses": [publicKey]]]
let request = createRequest(method: .simulateTransaction, parameters: [message, configuration])
let dataTask = urlSession.dataTask(with: request) { data, _, _ in
DispatchQueue.main.async {
if let data = data {
let raw = try? JSONSerialization.jsonObject(with: data)
completion(raw)
} else {
completion(nil)
}
}
}
dataTask.resume()
}
private func compileTransactionData(message: String, signature: String, simulation: Bool) -> String? {
guard let messageData = Base58.decodeNoCheck(string: message),
let signatureData = Base58.decodeNoCheck(string: signature) else { return nil }
let numberOfSignatures = messageData.requiredSignaturesCount
let placeholderSignature = Data(repeating: 0, count: 64)
var result = Data()
let encodedSignatureLength = Data.encodeLength(numberOfSignatures)
result = encodedSignatureLength + (simulation ? placeholderSignature : signatureData)
for _ in 0..<(numberOfSignatures - 1) {
result += placeholderSignature
}
result += messageData
return Base58.encodeNoCheck(data: result)
}
private func updateBlockhash(message: String, completion: @escaping (String?) -> Void) {
guard var data = Base58.decodeNoCheck(string: message) else {
completion(nil)
return
}
getLatestBlockhash { blockhash in
guard let blockhash = blockhash,
let numRequiredSignatures = data.popFirst(),
let numReadonlySignedAccounts = data.popFirst(),
let numReadonlyUnsignedAccounts = data.popFirst(),
let blockhashData = Base58.decodeNoCheck(string: blockhash) else {
completion(nil)
return
}
let numberOfBytes = 32
let accountCount = data.decodeLength()
let blockhashStartIndex = data.index(data.startIndex, offsetBy: numberOfBytes * accountCount)
let blockhashEndIndex = data.index(blockhashStartIndex, offsetBy: numberOfBytes)
data.replaceSubrange(blockhashStartIndex..<blockhashEndIndex, with: blockhashData)
data = Data.encodeLength(accountCount) + data
data = Data([numRequiredSignatures, numReadonlySignedAccounts, numReadonlyUnsignedAccounts]) + data
completion(Base58.encodeNoCheck(data: data))
}
}
}
// https://github.com/p2p-org/solana-swift/blob/main/Sources/SolanaSwift/Extensions/Data%2BExtensions.swift
private extension Data {
var requiredSignaturesCount: Int {
if let first = first {
return Int(first)
} else {
return 0
}
}
var decodedLength: Int {
var len = 0
var size = 0
var bytes = self
while true {
guard let elem = bytes.first else { break }
bytes = bytes.dropFirst()
len = len | ((Int(elem) & 0x7f) << (size * 7))
size += 1
if Int16(elem) & 0x80 == 0 {
break
}
}
return len
}
mutating func decodeLength() -> Int {
var len = 0
var size = 0
while true {
guard let elem = bytes.first else { break }
_ = popFirst()
len = len | ((Int(elem) & 0x7f) << (size * 7))
size += 1
if Int16(elem) & 0x80 == 0 {
break
}
}
return len
}
static func encodeLength(_ len: Int) -> Data {
encodeLength(UInt(len))
}
private static func encodeLength(_ len: UInt) -> Data {
var remLen = len
var bytes = Data()
while true {
var elem = remLen & 0x7f
remLen = remLen >> 7
if remLen == 0 {
bytes.append(UInt8(elem))
break
} else {
elem = elem | 0x80
bytes.append(UInt8(elem))
}
}
return bytes
}
}

View File

@ -76,5 +76,6 @@ struct Strings {
static let calculating = "Calculating…"
static let howToEnableSafariExtension = "How to enable Safari extension?"
static let shareInvite = "Share an invite"
static let approveTransaction = "Approve Transaction"
}

View File

@ -7,8 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
0A35995B64EBF9C1B79FFADF /* Pods_Tokenary_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE9E1A64A4B68CD2CC762C5C /* Pods_Tokenary_iOS.framework */; };
0D059AD226C2796200EE3023 /* ApprovalSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D059AD126C2796200EE3023 /* ApprovalSubject.swift */; };
0D82ED97B38BA6F113762E82 /* Pods_Tokenary_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF0BA09057BCB2C4011D0C5E /* Pods_Tokenary_iOS.framework */; };
0DC850E726B73A5900809E82 /* AuthenticationReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DC850E626B73A5900809E82 /* AuthenticationReason.swift */; };
2C03D1D2269B407900EF10EA /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C03D1D1269B407900EF10EA /* NetworkMonitor.swift */; };
2C03D1D5269B428C00EF10EA /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C03D1D4269B428C00EF10EA /* Notification.swift */; };
@ -64,6 +64,8 @@
2C264BEB27B6B50700234393 /* DappRequestProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C264BEA27B6B50700234393 /* DappRequestProcessor.swift */; };
2C264BEC27B6B50700234393 /* DappRequestProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C264BEA27B6B50700234393 /* DappRequestProcessor.swift */; };
2C3B7F022756A08600931264 /* Identifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3B7F012756A08600931264 /* Identifiers.swift */; };
2C40379428199110004C7263 /* Solana.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C40379328199110004C7263 /* Solana.swift */; };
2C40379528199110004C7263 /* Solana.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C40379328199110004C7263 /* Solana.swift */; };
2C40709027667A6600AB3D55 /* MultilineLabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C40708E27667A6600AB3D55 /* MultilineLabelTableViewCell.swift */; };
2C40709127667A6600AB3D55 /* MultilineLabelTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C40708F27667A6600AB3D55 /* MultilineLabelTableViewCell.xib */; };
2C40709427667A8600AB3D55 /* ImageWithLabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C40709227667A8600AB3D55 /* ImageWithLabelTableViewCell.swift */; };
@ -188,7 +190,7 @@
2CF255BA275A749300AE54B9 /* ApproveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CF255B9275A749300AE54B9 /* ApproveViewController.swift */; };
2CFDDF4C2765416F00F89019 /* macos-specific-content.js in Resources */ = {isa = PBXBuildFile; fileRef = 2CFDDF4B2765416F00F89019 /* macos-specific-content.js */; };
2CFDDF4E2765417E00F89019 /* ios-specific-content.js in Resources */ = {isa = PBXBuildFile; fileRef = 2CFDDF4D2765417D00F89019 /* ios-specific-content.js */; };
9CF0E61C7E25270AFD7B66BC /* Pods_Tokenary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 748E4E402F96890CD86451CD /* Pods_Tokenary.framework */; };
E1F659197E90BA26C3A3A6EE /* Pods_Tokenary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80697A23D681CBF87CF830B1 /* Pods_Tokenary.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -267,6 +269,7 @@
2C264BE527B5AC6800234393 /* TezosResponseToExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TezosResponseToExtension.swift; sourceTree = "<group>"; };
2C264BEA27B6B50700234393 /* DappRequestProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DappRequestProcessor.swift; sourceTree = "<group>"; };
2C3B7F012756A08600931264 /* Identifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Identifiers.swift; sourceTree = "<group>"; };
2C40379328199110004C7263 /* Solana.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Solana.swift; sourceTree = "<group>"; };
2C40708E27667A6600AB3D55 /* MultilineLabelTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineLabelTableViewCell.swift; sourceTree = "<group>"; };
2C40708F27667A6600AB3D55 /* MultilineLabelTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MultilineLabelTableViewCell.xib; sourceTree = "<group>"; };
2C40709227667A8600AB3D55 /* ImageWithLabelTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageWithLabelTableViewCell.swift; sourceTree = "<group>"; };
@ -365,12 +368,12 @@
2CF255B9275A749300AE54B9 /* ApproveViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApproveViewController.swift; sourceTree = "<group>"; };
2CFDDF4B2765416F00F89019 /* macos-specific-content.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "macos-specific-content.js"; sourceTree = "<group>"; };
2CFDDF4D2765417D00F89019 /* ios-specific-content.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "ios-specific-content.js"; sourceTree = "<group>"; };
3A44A6AD75AD00A8147D51C9 /* Pods-Tokenary iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tokenary iOS.release.xcconfig"; path = "Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS.release.xcconfig"; sourceTree = "<group>"; };
748E4E402F96890CD86451CD /* Pods_Tokenary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tokenary.framework; sourceTree = BUILT_PRODUCTS_DIR; };
79196256009C6E698EB7AA59 /* Pods-Tokenary.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tokenary.release.xcconfig"; path = "Target Support Files/Pods-Tokenary/Pods-Tokenary.release.xcconfig"; sourceTree = "<group>"; };
79E83B47DE0EB9BC8AC9B236 /* Pods-Tokenary iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tokenary iOS.debug.xcconfig"; path = "Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS.debug.xcconfig"; sourceTree = "<group>"; };
9FB2D4E7F11F60183689311C /* Pods-Tokenary.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tokenary.debug.xcconfig"; path = "Target Support Files/Pods-Tokenary/Pods-Tokenary.debug.xcconfig"; sourceTree = "<group>"; };
BE9E1A64A4B68CD2CC762C5C /* Pods_Tokenary_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tokenary_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3238B55CC74B94A606D08A98 /* Pods-Tokenary iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tokenary iOS.debug.xcconfig"; path = "Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS.debug.xcconfig"; sourceTree = "<group>"; };
3819EB5B48C6943F202EA8A0 /* Pods-Tokenary.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tokenary.release.xcconfig"; path = "Target Support Files/Pods-Tokenary/Pods-Tokenary.release.xcconfig"; sourceTree = "<group>"; };
599AA1113E7986A6414E0CD9 /* Pods-Tokenary iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tokenary iOS.release.xcconfig"; path = "Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS.release.xcconfig"; sourceTree = "<group>"; };
6FB8D9A5870F897C5CA4D898 /* Pods-Tokenary.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tokenary.debug.xcconfig"; path = "Target Support Files/Pods-Tokenary/Pods-Tokenary.debug.xcconfig"; sourceTree = "<group>"; };
80697A23D681CBF87CF830B1 /* Pods_Tokenary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tokenary.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FF0BA09057BCB2C4011D0C5E /* Pods_Tokenary_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tokenary_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -385,7 +388,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9CF0E61C7E25270AFD7B66BC /* Pods_Tokenary.framework in Frameworks */,
E1F659197E90BA26C3A3A6EE /* Pods_Tokenary.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -393,7 +396,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0A35995B64EBF9C1B79FFADF /* Pods_Tokenary_iOS.framework in Frameworks */,
0D82ED97B38BA6F113762E82 /* Pods_Tokenary_iOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -422,6 +425,15 @@
path = Models;
sourceTree = "<group>";
};
2A7484A18D772B4233D171DA /* Frameworks */ = {
isa = PBXGroup;
children = (
80697A23D681CBF87CF830B1 /* Pods_Tokenary.framework */,
FF0BA09057BCB2C4011D0C5E /* Pods_Tokenary_iOS.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
2C09CBA0273979C1009AD39B /* Safari macOS */ = {
isa = PBXGroup;
children = (
@ -454,7 +466,7 @@
2C5FF98A26C8567D00B32ACC /* Screensaver */,
2C19953D2674C4B900A8E370 /* Products */,
FB5786212D81829B0FADBD25 /* Pods */,
3C02E73226D93B28BA7E14DD /* Frameworks */,
2A7484A18D772B4233D171DA /* Frameworks */,
);
sourceTree = "<group>";
};
@ -781,6 +793,7 @@
children = (
2C03D1D1269B407900EF10EA /* NetworkMonitor.swift */,
2C264BEA27B6B50700234393 /* DappRequestProcessor.swift */,
2C40379328199110004C7263 /* Solana.swift */,
2CAA412426C7CD93009F3535 /* ReviewRequester.swift */,
2C901C4C268A033100D0926A /* GasService.swift */,
2CC0CDBD2692027E0072922A /* PriceService.swift */,
@ -809,22 +822,13 @@
path = Screens;
sourceTree = "<group>";
};
3C02E73226D93B28BA7E14DD /* Frameworks */ = {
isa = PBXGroup;
children = (
748E4E402F96890CD86451CD /* Pods_Tokenary.framework */,
BE9E1A64A4B68CD2CC762C5C /* Pods_Tokenary_iOS.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
FB5786212D81829B0FADBD25 /* Pods */ = {
isa = PBXGroup;
children = (
9FB2D4E7F11F60183689311C /* Pods-Tokenary.debug.xcconfig */,
79196256009C6E698EB7AA59 /* Pods-Tokenary.release.xcconfig */,
79E83B47DE0EB9BC8AC9B236 /* Pods-Tokenary iOS.debug.xcconfig */,
3A44A6AD75AD00A8147D51C9 /* Pods-Tokenary iOS.release.xcconfig */,
6FB8D9A5870F897C5CA4D898 /* Pods-Tokenary.debug.xcconfig */,
3819EB5B48C6943F202EA8A0 /* Pods-Tokenary.release.xcconfig */,
3238B55CC74B94A606D08A98 /* Pods-Tokenary iOS.debug.xcconfig */,
599AA1113E7986A6414E0CD9 /* Pods-Tokenary iOS.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -865,13 +869,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 2C19954C2674C4BA00A8E370 /* Build configuration list for PBXNativeTarget "Tokenary" */;
buildPhases = (
032A6C803438BB662CB91D5C /* [CP] Check Pods Manifest.lock */,
5ED94A042948552AFC0B9216 /* [CP] Check Pods Manifest.lock */,
2C1995382674C4B900A8E370 /* Sources */,
2C1995392674C4B900A8E370 /* Frameworks */,
2C19953A2674C4B900A8E370 /* Resources */,
2C1995512674C6A100A8E370 /* ShellScript */,
2C09CBB8273979C1009AD39B /* Embed App Extensions */,
E992E558A2E6E14778576867 /* [CP] Embed Pods Frameworks */,
2B67825D537A2599798098F3 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -887,13 +891,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 2C5FF98026C84F7C00B32ACC /* Build configuration list for PBXNativeTarget "Tokenary iOS" */;
buildPhases = (
9283FF1ED099C56D5CD4C47F /* [CP] Check Pods Manifest.lock */,
111F85DD9343C4B33301D00C /* [CP] Check Pods Manifest.lock */,
2C5FF96B26C84F7B00B32ACC /* Sources */,
2C5FF96C26C84F7B00B32ACC /* Frameworks */,
2C5FF96D26C84F7B00B32ACC /* Resources */,
2CC8C59D27678D4B0083FB1B /* ShellScript */,
2CCEB84627594E2A00768473 /* Embed App Extensions */,
3D6DA0588EFAC21D933260AA /* [CP] Embed Pods Frameworks */,
68842E1F5932B8E151C67B04 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -1055,7 +1059,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
032A6C803438BB662CB91D5C /* [CP] Check Pods Manifest.lock */ = {
111F85DD9343C4B33301D00C /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -1070,13 +1074,30 @@
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Tokenary-checkManifestLockResult.txt",
"$(DERIVED_FILE_DIR)/Pods-Tokenary iOS-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
2B67825D537A2599798098F3 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Tokenary/Pods-Tokenary-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Tokenary/Pods-Tokenary-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tokenary/Pods-Tokenary-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
2C1995512674C6A100A8E370 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -1147,24 +1168,7 @@
shellPath = /bin/sh;
shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which swiftlint; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
3D6DA0588EFAC21D933260AA /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9283FF1ED099C56D5CD4C47F /* [CP] Check Pods Manifest.lock */ = {
5ED94A042948552AFC0B9216 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -1179,28 +1183,28 @@
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Tokenary iOS-checkManifestLockResult.txt",
"$(DERIVED_FILE_DIR)/Pods-Tokenary-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
E992E558A2E6E14778576867 /* [CP] Embed Pods Frameworks */ = {
68842E1F5932B8E151C67B04 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Tokenary/Pods-Tokenary-frameworks-${CONFIGURATION}-input-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Tokenary/Pods-Tokenary-frameworks-${CONFIGURATION}-output-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tokenary/Pods-Tokenary-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tokenary iOS/Pods-Tokenary iOS-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@ -1288,6 +1292,7 @@
2C264BDC27B5AC5400234393 /* EthereumResponseToExtension.swift in Sources */,
2C03D1D5269B428C00EF10EA /* Notification.swift in Sources */,
2C1995562674D0F300A8E370 /* Ethereum.swift in Sources */,
2C40379428199110004C7263 /* Solana.swift in Sources */,
2C8A09DF267579EA00993638 /* AccountsListViewController.swift in Sources */,
2C917429267D2A6E00049075 /* Keychain.swift in Sources */,
);
@ -1341,6 +1346,7 @@
2CF2559C275A477F00AE54B9 /* ApprovalSubject.swift in Sources */,
2C264BE727B5AC6800234393 /* TezosResponseToExtension.swift in Sources */,
2C264BD627B5806200234393 /* Web3Provider.swift in Sources */,
2C40379528199110004C7263 /* Solana.swift in Sources */,
2CE0594427640EB40042D844 /* ExtensionBridge.swift in Sources */,
2CF255B1275A4A1800AE54B9 /* ResponseToExtension.swift in Sources */,
2CF2559B275A46E700AE54B9 /* AuthenticationReason.swift in Sources */,
@ -1619,7 +1625,7 @@
};
2C19954D2674C4BA00A8E370 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9FB2D4E7F11F60183689311C /* Pods-Tokenary.debug.xcconfig */;
baseConfigurationReference = 6FB8D9A5870F897C5CA4D898 /* Pods-Tokenary.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
@ -1647,7 +1653,7 @@
};
2C19954E2674C4BA00A8E370 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 79196256009C6E698EB7AA59 /* Pods-Tokenary.release.xcconfig */;
baseConfigurationReference = 3819EB5B48C6943F202EA8A0 /* Pods-Tokenary.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
@ -1675,7 +1681,7 @@
};
2C5FF98126C84F7C00B32ACC /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 79E83B47DE0EB9BC8AC9B236 /* Pods-Tokenary iOS.debug.xcconfig */;
baseConfigurationReference = 3238B55CC74B94A606D08A98 /* Pods-Tokenary iOS.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
@ -1701,7 +1707,7 @@
};
2C5FF98226C84F7C00B32ACC /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3A44A6AD75AD00A8147D51C9 /* Pods-Tokenary iOS.release.xcconfig */;
baseConfigurationReference = 599AA1113E7986A6414E0CD9 /* Pods-Tokenary iOS.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;