Skip to content

Commit 13efcab

Browse files
committed
Merge branch 'election-verification' of github.com:Concordium/concordium.github.io into election-verification
2 parents f6f9c0c + 0adfcdf commit 13efcab

8 files changed

+366
-13
lines changed

Pipfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ doc8 = "*"
2020
sphinx-autobuild = "*"
2121

2222
[requires]
23-
python_version = "3.11"
23+
python_version = "3.12"

source/mainnet/net/guides/wallet-sdk/wallet-sdk-account-transaction.rst

+47-2
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,54 @@ Note that when the transaction has been signed anyone with the signature and the
143143
144144
.. tab::
145145

146-
Swift (iOS)
146+
Swift (macOS, iOS)
147+
148+
.. code-block:: Swift
149+
150+
import Concordium
151+
152+
// Inputs.
153+
let seedPhrase = "fence tongue sell large master side flock bronze ice accident what humble bring heart swear record valley party jar caution horn cushion endorse position"
154+
let network = Network.testnet
155+
let identityProviderID = IdentityProviderID(3)
156+
let identityIndex = IdentityIndex(7)
157+
let credentialCounter = CredentialCounter(21)
158+
let amount = MicroCCDAmount(1337)
159+
let receiver = try! AccountAddress(base58Check: "33Po4Z5v4DaAHo9Gz9Afc9LRzbZmYikus4Q7gqMaXHtdS17khz")
160+
let expiry = TransactionTime(9_999_999_999)
161+
162+
/// Perform a transfer based on the inputs above.
163+
func transfer(client: NodeClient) async throws {
164+
let seed = try decodeSeed(seedPhrase, network)
165+
166+
// Derive seed based account from the given coordinates of the given seed.
167+
let cryptoParams = try await client.cryptographicParameters(block: .lastFinal)
168+
let accountDerivation = SeedBasedAccountDerivation(seed: seed, cryptoParams: cryptoParams)
169+
let credentialIndexes = AccountCredentialSeedIndexes(
170+
identity: .init(providerID: identityProviderID, index: identityIndex),
171+
counter: credentialCounter
172+
)
173+
let account = try accountDerivation.deriveAccount(credentials: [credentialIndexes])
174+
175+
// Construct, sign, and send transfer transaction.
176+
let nextSeq = try await client.nextAccountSequenceNumber(address: account.address)
177+
let tx = try makeTransfer(account, amount, receiver, nextSeq.sequenceNumber, expiry)
178+
let hash = try await client.send(transaction: tx)
179+
print("Transaction with hash '\(hash.hex)' successfully submitted.")
180+
}
181+
182+
/// Construct and sign transfer transaction.
183+
func makeTransfer(
184+
_ account: Account,
185+
_ amount: MicroCCDAmount,
186+
_ receiver: AccountAddress,
187+
_ seq: SequenceNumber,
188+
_ expiry: TransactionTime
189+
) throws -> SignedAccountTransaction {
190+
let tx = AccountTransaction(sender: account.address, payload: .transfer(amount: amount, receiver: receiver))
191+
return try account.keys.sign(transaction: tx, sequenceNumber: seq, expiry: expiry)
192+
}
147193
148-
The Swift SDK for iOS is still in development.
149194
150195
++++++++++++++++++++++++++++++++++++++++++++++++
151196
Send an account transaction to a Concordium node

source/mainnet/net/guides/wallet-sdk/wallet-sdk-credential-deployment.rst

+75-2
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,82 @@ The following example demonstrates how a credential deployment transaction is cr
180180
181181
.. tab::
182182

183-
Swift (iOS)
183+
Swift (macOS, iOS)
184+
185+
.. code-block:: Swift
186+
187+
import Concordium
188+
import Foundation
189+
190+
// Inputs.
191+
let seedPhrase = "fence tongue sell large master side flock bronze ice accident what humble bring heart swear record valley party jar caution horn cushion endorse position"
192+
let network = Network.testnet
193+
let identityProviderID = IdentityProviderID(3)
194+
let identityIndex = IdentityIndex(7)
195+
let credentialCounter = CredentialCounter(21)
196+
let walletProxyBaseURL = URL(string: "https://wallet-proxy.testnet.concordium.com")!
197+
let anonymityRevocationThreshold = RevocationThreshold(2)
198+
let expiry = TransactionTime(9_999_999_999)
199+
200+
/// Perform account creation (on recovered identity) based on the inputs above.
201+
func createAccount(client: NodeClient) async throws {
202+
let seed = try decodeSeed(seedPhrase, network)
203+
let walletProxy = WalletProxy(baseURL: walletProxyBaseURL)
204+
let identityProvider = try await findIdentityProvider(walletProxy, identityProviderID)!
205+
206+
// Recover identity (not necessary if the ID is already stored).
207+
// This assumes that the identity already exists, of course.
208+
let cryptoParams = try await client.cryptographicParameters(block: .lastFinal)
209+
let identityReq = try makeIdentityRecoveryRequest(seed, cryptoParams, identityProvider, identityIndex)
210+
let identity = try await identityReq.send(session: URLSession.shared)
211+
212+
// Derive seed based credential and account from the given coordinates of the given seed.
213+
let accountDerivation = SeedBasedAccountDerivation(seed: seed, cryptoParams: cryptoParams)
214+
let seedIndexes = AccountCredentialSeedIndexes(
215+
identity: .init(providerID: identityProviderID, index: identityIndex),
216+
counter: credentialCounter
217+
)
218+
// Credential to deploy.
219+
let credential = try accountDerivation.deriveCredential(
220+
seedIndexes: seedIndexes,
221+
identity: identity.value,
222+
provider: identityProvider,
223+
threshold: 1
224+
)
225+
// Account used to sign the deployment.
226+
// The account is composed from just the credential derived above.
227+
// From this call the credential's signing key will be derived;
228+
// in the previous only the public key was.
229+
let account = try accountDerivation.deriveAccount(credentials: [seedIndexes])
230+
231+
// Construct, sign, and send deployment transaction.
232+
let signedTx = try account.keys.sign(deployment: credential, expiry: expiry)
233+
let serializedTx = try signedTx.serialize()
234+
let hash = try await client.send(deployment: serializedTx)
235+
print("Transaction with hash '\(hash.hex)' successfully submitted.")
236+
}
184237
185-
The Swift SDK for iOS is still in development.
238+
func makeIdentityRecoveryRequest(
239+
_ seed: WalletSeed,
240+
_ cryptoParams: CryptographicParameters,
241+
_ identityProvider: IdentityProvider,
242+
_ identityIndex: IdentityIndex
243+
) throws -> IdentityRecoverRequest {
244+
let identityRequestBuilder = SeedBasedIdentityRequestBuilder(
245+
seed: seed,
246+
cryptoParams: cryptoParams
247+
)
248+
let reqJSON = try identityRequestBuilder.recoveryRequestJSON(
249+
provider: identityProvider.info,
250+
index: identityIndex,
251+
time: Date.now
252+
)
253+
let urlBuilder = IdentityRequestURLBuilder(callbackURL: nil)
254+
return try urlBuilder.recoveryRequest(
255+
baseURL: identityProvider.metadata.recoveryStart,
256+
requestJSON: reqJSON
257+
)
258+
}
186259
187260
++++++++++++++++++++++++++++++++++++++++
188261
Sign a credential deployment transaction

source/mainnet/net/guides/wallet-sdk/wallet-sdk-identity-creation.rst

+93-2
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,100 @@ The first step is to create the actual identity request. To do this, you need th
140140
141141
.. tab::
142142

143-
Swift (iOS)
143+
Swift (macOS, iOS)
144+
145+
.. code-block:: Swift
146+
147+
import Concordium
148+
import Foundation
149+
150+
// Inputs.
151+
let seedPhrase = "fence tongue sell large master side flock bronze ice accident what humble bring heart swear record valley party jar caution horn cushion endorse position"
152+
let network = Network.testnet
153+
let identityProviderID = IdentityProviderID(3)
154+
let identityIndex = IdentityIndex(7)
155+
let walletProxyBaseURL = URL(string: "https://wallet-proxy.testnet.concordium.com")!
156+
let anonymityRevocationThreshold = RevocationThreshold(2)
157+
158+
/// Perform an identity creation based on the inputs above.
159+
func createIdentity(client: NodeClient) async throws {
160+
let seed = try decodeSeed(seedPhrase, network)
161+
let walletProxy = WalletProxy(baseURL: walletProxyBaseURL)
162+
let identityProvider = try await findIdentityProvider(walletProxy, identityProviderID)!
163+
164+
// Construct identity creation request and start verification.
165+
let cryptoParams = try await client.cryptographicParameters(block: .lastFinal)
166+
let identityReq = try issueIdentitySync(seed, cryptoParams, identityProvider, identityIndex, anonymityRevocationThreshold) { issuanceStartURL, requestJSON in
167+
// The URL to be invoked when once the ID verification process has started (i.e. once the data has been filled in).
168+
let callbackURL = URL(string: "concordiumwallet-example://identity-issuer/callback")!
169+
170+
let urlBuilder = IdentityRequestURLBuilder(callbackURL: callbackURL)
171+
let url = try urlBuilder.issuanceURLToOpen(baseURL: issuanceStartURL, requestJSON: requestJSON)
172+
todoOpenURL(url)
173+
174+
return todoAwaitCallbackWithVerificationPollingURL()
175+
}
144176
145-
The Swift SDK for iOS is still in development.
177+
let res = try await todoFetchIdentityIssuance(identityReq)
178+
if case let .success(identity) = res {
179+
print("Identity issued successfully: \(identity))")
180+
} else {
181+
// Verification failed...
182+
}
183+
}
184+
185+
func issueIdentitySync(
186+
_ seed: WalletSeed,
187+
_ cryptoParams: CryptographicParameters,
188+
_ identityProvider: IdentityProvider,
189+
_ identityIndex: IdentityIndex,
190+
_ anonymityRevocationThreshold: RevocationThreshold,
191+
_ runIdentityProviderFlow: (_ issuanceStartURL: URL, _ requestJSON: String) throws -> URL
192+
) throws -> IdentityIssuanceRequest {
193+
print("Preparing identity issuance request.")
194+
let identityRequestBuilder = SeedBasedIdentityRequestBuilder(
195+
seed: seed,
196+
cryptoParams: cryptoParams
197+
)
198+
let reqJSON = try identityRequestBuilder.issuanceRequestJSON(
199+
provider: identityProvider,
200+
index: identityIndex,
201+
anonymityRevocationThreshold: anonymityRevocationThreshold
202+
)
203+
204+
print("Start identity provider issuance flow.")
205+
let url = try runIdentityProviderFlow(identityProvider.metadata.issuanceStart, reqJSON)
206+
print("Identity verification process started!")
207+
return .init(url: url)
208+
}
209+
210+
func todoOpenURL(_: URL) {
211+
// Open the URL in a web view to start the identity verification flow with the identity provider.
212+
fatalError("'openURL' not implemented")
213+
}
214+
215+
func todoAwaitCallbackWithVerificationPollingURL() -> URL {
216+
// Block the thread and wait for the callback URL to be invoked (and somehow capture that event).
217+
// In mobile wallets, the callback URL is probably a deep link that we listen on somewhere else.
218+
// In that case, this snippet would be done now and we would expect the handler to be eventually invoked.
219+
// In either case, the callback is how the IP hands over the URL for polling the verification status -
220+
// and for some reason it does so in the *fragment* part of the URL!
221+
// See 'server.swift' of the example CLI for a server-based solution that works in a synchronous context.
222+
// Warning: It ain't pretty.
223+
fatalError("'awaitCallbackWithVerificationPollingURL' not implemented")
224+
}
225+
226+
func todoFetchIdentityIssuance(_ request: IdentityIssuanceRequest) async throws -> IdentityVerificationResult {
227+
// Block the thread, periodically polling for the verification status.
228+
// Return the result once it's no longer "pending" (i.e. the result is non-nil).
229+
while true {
230+
let status = try await request.send(session: URLSession.shared)
231+
if let r = status.result {
232+
return r
233+
}
234+
try await Task.sleep(nanoseconds: 10 * 1_000_000_000) // check once every 10s
235+
}
236+
}
146237
147238
++++++++++++++++++++++++
148239
Send an identity request

source/mainnet/net/guides/wallet-sdk/wallet-sdk-identity-provider.rst

+14-2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ Here is an example of how the list of identity providers can be retrieved from t
9797
9898
.. tab::
9999

100-
Swift (iOS)
100+
Swift (macOS, iOS)
101101

102-
The Swift SDK for iOS is still in development.
102+
.. code-block:: Swift
103+
104+
import Concordium
105+
import Foundation
106+
107+
// Inputs.
108+
let walletProxyBaseURL = URL(string: "https://wallet-proxy.testnet.concordium.com")!
109+
110+
let walletProxy = WalletProxy(baseURL: walletProxyBaseURL)
111+
print("Identity providers:")
112+
for ip in try await identityProviders(walletProxy) {
113+
print("- \(ip.info.description.name)")
114+
}

source/mainnet/net/guides/wallet-sdk/wallet-sdk-identity-recovery.rst

+51-2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,55 @@ The next step is to send the generated identity recovery request to the associat
197197
198198
.. tab::
199199

200-
Swift (iOS)
200+
Swift (macOS, iOS)
201+
202+
.. code-block:: Swift
203+
204+
import Concordium
205+
import Foundation
206+
207+
// Inputs.
208+
let seedPhrase = "fence tongue sell large master side flock bronze ice accident what humble bring heart swear record valley party jar caution horn cushion endorse position"
209+
let network = Network.testnet
210+
let identityProviderID = IdentityProviderID(3)
211+
let identityIndex = IdentityIndex(7)
212+
let walletProxyBaseURL = URL(string: "https://wallet-proxy.testnet.concordium.com")!
213+
let anonymityRevocationThreshold = RevocationThreshold(2)
214+
215+
/// Perform identity recovery based on the inputs above.
216+
func recoverIdentity(client: NodeClient) async throws {
217+
let seed = try decodeSeed(seedPhrase, network)
218+
let walletProxy = WalletProxy(baseURL: walletProxyBaseURL)
219+
let identityProvider = try await findIdentityProvider(walletProxy, identityProviderID)!
220+
221+
// Construct recovery request.
222+
let cryptoParams = try await client.cryptographicParameters(block: .lastFinal)
223+
let identityReq = try makeIdentityRecoveryRequest(seed, cryptoParams, identityProvider, identityIndex)
224+
225+
// Execute request.
226+
let identity = try await identityReq.send(session: URLSession.shared)
227+
print("Successfully recovered identity: \(identity)")
228+
}
201229
202-
The Swift SDK for iOS is still in development.
230+
// Duplicated in 'CreateAccount/main.swift'.
231+
func makeIdentityRecoveryRequest(
232+
_ seed: WalletSeed,
233+
_ cryptoParams: CryptographicParameters,
234+
_ identityProvider: IdentityProvider,
235+
_ identityIndex: IdentityIndex
236+
) throws -> IdentityRecoverRequest {
237+
let identityRequestBuilder = SeedBasedIdentityRequestBuilder(
238+
seed: seed,
239+
cryptoParams: cryptoParams
240+
)
241+
let reqJSON = try identityRequestBuilder.recoveryRequestJSON(
242+
provider: identityProvider.info,
243+
index: identityIndex,
244+
time: Date.now
245+
)
246+
let urlBuilder = IdentityRequestURLBuilder(callbackURL: nil)
247+
return try urlBuilder.recoveryRequest(
248+
baseURL: identityProvider.metadata.recoveryStart,
249+
requestJSON: reqJSON
250+
)
251+
}

source/mainnet/net/guides/wallet-sdk/wallet-sdk.rst

+9-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,16 @@ Below, you can find a link to the SDK package for your chosen technology, and an
3737
3838
.. tab::
3939

40-
Swift (iOS)
40+
Swift (macOS, iOS)
4141

42-
The Swift SDK for iOS is still in development.
42+
| Swift Package
43+
| `concordium-swift-sdk <https://github.com/Concordium/concordium-swift-sdk>`
44+
45+
| Working example implementation of a CLI tool for macOS
46+
| https://github.com/Concordium/concordium-swift-sdk/tree/main/examples/CLI
47+
48+
| Code snippets used in this documentation
49+
| https://github.com/Concordium/concordium-swift-sdk/tree/main/examples/DocSnippets
4350
4451
.. toctree::
4552
:hidden:

0 commit comments

Comments
 (0)