Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ID 2.5 + encrypted balance #69

Merged
merged 29 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f6b8256
Encode/decode relevant id proof types
soerenbf Sep 20, 2024
2d852d5
Replicate generic implementation of proofs/statements to ease
soerenbf Sep 23, 2024
d32c10b
Add `Statement.prove` for constructing a proof for a statement
soerenbf Sep 23, 2024
910fd67
Add unit test for (ID) statement/proof
soerenbf Sep 23, 2024
f850436
Expose functionality for working with encrypted amounts
soerenbf Sep 23, 2024
2e6edd2
Align to ID proof changes
soerenbf Sep 25, 2024
0ebd709
Migrate types to FFI lib
soerenbf Sep 26, 2024
429185f
Implement web3id types codable
soerenbf Sep 27, 2024
6da6848
Align examples to changes
soerenbf Sep 27, 2024
f275161
Decode wallet connect request for verifiable presentation
soerenbf Sep 27, 2024
30cfefa
Create verifiable presentation from request, context and commitments
soerenbf Oct 1, 2024
5020428
verifiable presentation codability works
soerenbf Oct 1, 2024
418601d
Web3IdCredential + builder for verifiable presentation
soerenbf Oct 1, 2024
d6d468c
Web3IdCredential Codable conformance
soerenbf Oct 2, 2024
74983b5
Unit test for `VerifiablePresentationBuilder` to examplify use
soerenbf Oct 2, 2024
0d32e84
Document wallet seed
soerenbf Oct 3, 2024
b910c26
Document proof types
soerenbf Oct 3, 2024
f1197d1
Update examples
soerenbf Oct 3, 2024
c5e853a
Update changelog
soerenbf Oct 3, 2024
5f21a90
Unit test walletconnect verifiable presentation request
soerenbf Oct 3, 2024
8dbb30e
Add remaining unit tests for walletconnect variants
soerenbf Oct 3, 2024
218111c
changelog sections
soerenbf Oct 3, 2024
276ac6b
Merge branch 'main' into mobile-wallet-feature-parity
soerenbf Oct 4, 2024
45c9dd2
FMT
soerenbf Oct 4, 2024
dd7e566
Presentation builder set eq + check values for adding verification rows
soerenbf Oct 7, 2024
cda4f28
Unit test for statement checking
soerenbf Oct 7, 2024
1b3bd07
Adapt to changes in FFI lib
soerenbf Oct 8, 2024
233451a
Update FFI lib
soerenbf Oct 9, 2024
4085335
Make retroactive protocol conformance backwards compatible
soerenbf Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Support for all transactions relevant from protocol version 7 and onwards. This includes expanding `AccountTransactionPayload`
with the necessary variants, and corresponding constructor functions for `AccountTransaction`.
- `WalletConnectSendTransactionParam` and `WalletConnectSignMessageParam` for decoding parameters received with walletconnect requests.
- `BakerKeyPairs.generate` for generating baker keys
- `ContractSchema`, `TypeSchema`, and `ModuleSchema` for encoding/decoding data from/to the corresponding JSON representation
- `WalletSeed.encryptionKeys` to get the encryption keys for a credential index
- `decryptAmount` and `combineEncryptedAmounts` to handle encrypted amounts

#### ID proofs
- `Statement` and `Proof` types for constructing ID statements and their corresponding proofs
- `VerifiablePresentation`, `Web3IdCredential`, and `VerifiableCredentialStatement` types for representing verifiable credentials and constructing
verifiable presentations for these.
- `VerifiablePresentationBuilder` has been added to ease the construction of `VerifiablePresentation`s of a given statement in the context of a verifiable credential.

#### Walletconnect
- `WalletConnectSendTransactionParam`, `WalletConnectSignMessageParam`, and `WalletConnectRequestVerifiablePresentationParam` for decoding parameters received with walletconnect requests.
- `WalletConnectRequest` represents and decodes walletconnect request variants


#### GRPC client
- `NodeClient.status` to query transaction status.
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/Concordium/concordium-wallet-crypto-swift.git",
"state" : {
"revision" : "32e4c86bd6ad018ea381b0fffbb39520520e1985",
"version" : "4.1.0"
"revision" : "067a0288c7ed225ed47216c016ded0e1b43c8147",
"version" : "5.0.0"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ let package = Package(
.package(url: "https://github.com/bisgardo/Hextension.git", from: "1.0.1"),
overridableCryptoDependency(
url: "https://github.com/Concordium/concordium-wallet-crypto-swift.git",
from: "4.1.0"
from: "5.0.0"
),
],
targets: [
Expand Down
43 changes: 32 additions & 11 deletions Sources/Concordium/Domain/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public struct CredentialRegistrationID: Serialize, Deserialize, FromGRPC, ToGRPC
/// Get the ``AccountAddress`` corresonding to the credential registration ID.
public var accountAddress: AccountAddress {
let hash = SHA256.hash(data: value)
return AccountAddress(Data(hash))
return try! AccountAddress(Data(hash))
soerenbf marked this conversation as resolved.
Show resolved Hide resolved
}

public var hex: String { value.hex }
Expand Down Expand Up @@ -95,7 +95,7 @@ public typealias SignatureThreshold = UInt8
public typealias RevocationThreshold = UInt8

/// Amount of uCCD.
public typealias MicroCCDAmount = UInt64
public typealias MicroCCDAmount = ConcordiumWalletCrypto.MicroCCDAmount

public typealias EncryptedAmount = Data

Expand Down Expand Up @@ -171,7 +171,8 @@ public struct AccountAddress: Hashable, Serialize, Deserialize, ToGRPC, FromGRPC
}

/// Construct address directly from a 32-byte data buffer.
public init(_ data: Data) {
public init(_ data: Data) throws {
guard data.count == Self.SIZE else { throw ExactSizeError(actual: UInt(data.count), expected: UInt(Self.SIZE)) }
self.data = data
}

Expand All @@ -187,15 +188,15 @@ public struct AccountAddress: Hashable, Serialize, Deserialize, ToGRPC, FromGRPC
if version != Self.base58CheckVersion {
throw GRPCError.unexpectedBase58CheckVersion(expected: Self.base58CheckVersion, actual: version)
}
self.init(data) // excludes initial version byte
try self.init(data) // excludes initial version byte
}

public static func deserialize(_ data: inout Cursor) -> AccountAddress? {
data.read(num: SIZE).map { AccountAddress(Data($0)) }
try? data.read(num: SIZE).map { try AccountAddress(Data($0)) }
}

static func fromGRPC(_ grpc: GRPC) -> Self {
.init(grpc.value)
static func fromGRPC(_ grpc: GRPC) throws -> Self {
try .init(grpc.value)
}

public func serializeInto(buffer: inout NIOCore.ByteBuffer) -> Int {
Expand Down Expand Up @@ -405,7 +406,7 @@ extension VerifyKey: Codable {
}
}

extension VerifyKey: CustomStringConvertible {
extension ConcordiumWalletCrypto.VerifyKey: Swift.CustomStringConvertible {
public var description: String { "\(key.hex)" }
}

Expand All @@ -426,7 +427,7 @@ extension Policy: FromGRPC {
let attr = try UInt8(exactly: e.key)
.flatMap { AttributeTag(rawValue: $0) }
?! GRPCError.valueOutOfBounds
res["\(attr)"] = String(data: e.value, encoding: .utf8) // TODO: correct to treat attribute value as UTF-8?
res[attr] = String(data: e.value, encoding: .utf8) // TODO: correct to treat attribute value as UTF-8?
}
)
}
Expand All @@ -451,7 +452,7 @@ extension Policy: Codable {

let createdAtYearMonth = try container.decode(String.self, forKey: .createdAt)
let validToYearMonth = try container.decode(String.self, forKey: .validTo)
let revealedAttributes = try container.decode([String: String].self, forKey: .revealedAttributes)
let revealedAttributes = try container.decode([AttributeTag: String].self, forKey: .revealedAttributes)

self.init(createdAtYearMonth: createdAtYearMonth, validToYearMonth: validToYearMonth, revealedAttributes: revealedAttributes)
}
Expand Down Expand Up @@ -918,6 +919,9 @@ extension CredentialType: FromGRPC {
}
}

/// Details of an account creation. These transactions are free, and we only
/// ever get a response for them if the account is created, hence no failure
/// cases.
public struct AccountCreationDetails {
/// Whether this is an initial or normal account.
public let credentialType: CredentialType
Expand All @@ -932,8 +936,25 @@ extension AccountCreationDetails: FromGRPC {

static func fromGRPC(_ g: GRPC) throws -> AccountCreationDetails {
let credentialType = try CredentialType.fromGRPC(g.credentialType)
let address = AccountAddress.fromGRPC(g.address)
let address = try AccountAddress.fromGRPC(g.address)
let regId = try CredentialRegistrationID.fromGRPC(g.regID)
return Self(credentialType: credentialType, address: address, regId: regId)
}
}

/// Encryption keypair for an account, used to handle the encrypted amount associated with a specific account.
public typealias EncryptionKeys = ConcordiumWalletCrypto.EncryptionKeys

/// Decrypt a single encrypted amount using the secret key corresponding to the public key used for the encryption.
public func decryptAmount(encryptedAmount: Data, encryptionSecretKey: Data) throws -> CCD {
let amount = try ConcordiumWalletCrypto.decryptAmount(encryptedAmount: encryptedAmount, encryptionSecretKey: encryptionSecretKey)
return CCD(microCCD: amount)
}

/// Combine two encrypted amounts into one.
///
/// This is only meaningful if both encrypted amounts are encrypted with the
/// same public key, otherwise the result is meaningless.
public func combineEncryptedAmounts(left: Data, right: Data) throws -> Data {
try ConcordiumWalletCrypto.combineEncryptedAmounts(left: left, right: right)
}
22 changes: 11 additions & 11 deletions Sources/Concordium/Domain/Events.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extension AccountTransactionDetails: FromGRPC {

static func fromGRPC(_ g: GRPC) throws -> AccountTransactionDetails {
let cost = try CCD.fromGRPC(g.cost)
let sender = AccountAddress.fromGRPC(g.sender)
let sender = try AccountAddress.fromGRPC(g.sender)
let effects = try AccountTransactionEffects.fromGRPC(g.effects)
return Self(cost: cost, sender: sender, effects: effects)
}
Expand Down Expand Up @@ -101,7 +101,7 @@ extension AccountTransactionEffects: FromGRPC {
case let .transferredWithSchedule(data):
let schedule = try data.amount.map { try ScheduledTransfer.fromGRPC($0) }
let memo = data.hasMemo ? try Memo.fromGRPC(data.memo) : nil
return .transferredWithSchedule(to: .fromGRPC(data.receiver), schedule: schedule, memo: memo)
return try .transferredWithSchedule(to: .fromGRPC(data.receiver), schedule: schedule, memo: memo)
}
}
}
Expand Down Expand Up @@ -155,8 +155,8 @@ public struct BakerKeysEvent {
extension BakerKeysEvent: FromGRPC {
typealias GRPC = Concordium_V2_BakerKeysEvent

static func fromGRPC(_ g: GRPC) -> BakerKeysEvent {
.init(bakerId: g.bakerID.value, account: .fromGRPC(g.account), signKey: g.signKey.value, electionKey: g.electionKey.value, aggregationKey: g.aggregationKey.value)
static func fromGRPC(_ g: GRPC) throws -> BakerKeysEvent {
try .init(bakerId: g.bakerID.value, account: .fromGRPC(g.account), signKey: g.signKey.value, electionKey: g.electionKey.value, aggregationKey: g.aggregationKey.value)
}
}

Expand Down Expand Up @@ -192,7 +192,7 @@ extension BakerEvent: FromGRPC {
case let .bakerStakeIncreased(data):
return try .bakerStakeIncreased(bakerId: data.bakerID.value, newStake: .fromGRPC(data.newStake))
case let .bakerKeysUpdated(keys):
return .bakerSetKeys(.fromGRPC(keys))
return try .bakerSetKeys(.fromGRPC(keys))
case let .bakerSetBakingRewardCommission(data):
return .bakerSetBakingRewardCommission(bakerId: data.bakerID.value, commission: .fromGRPC(data.bakingRewardCommission))
case let .bakerSetFinalizationRewardCommission(data):
Expand Down Expand Up @@ -371,7 +371,7 @@ extension RejectReason: FromGRPC {
case let .duplicateCredIds(v):
return try .duplicateCredIDs(contents: v.ids.map { try .fromGRPC($0) })
case let .encryptedAmountSelfTransfer(v):
return .encryptedAmountSelfTransfer(contents: .fromGRPC(v))
return try .encryptedAmountSelfTransfer(contents: .fromGRPC(v))
case .finalizationRewardCommissionNotInRange:
return .finalizationRewardCommissionNotInRange
case .firstScheduledReleaseExpired:
Expand All @@ -383,7 +383,7 @@ extension RejectReason: FromGRPC {
case .insufficientDelegationStake:
return .insufficientDelegationStake
case let .invalidAccountReference(v):
return .invalidAccountReference(contents: .fromGRPC(v))
return try .invalidAccountReference(contents: .fromGRPC(v))
case .invalidAccountThreshold:
return .invalidAccountThreshold
case let .invalidContractAddress(v):
Expand Down Expand Up @@ -423,9 +423,9 @@ extension RejectReason: FromGRPC {
case .nonIncreasingSchedule:
return .nonIncreasingSchedule
case let .notABaker(v):
return .notABaker(contents: .fromGRPC(v))
return try .notABaker(contents: .fromGRPC(v))
case let .notADelegator(v):
return .notADelegator(contents: .fromGRPC(v))
return try .notADelegator(contents: .fromGRPC(v))
case .notAllowedMultipleCredentials:
return .notAllowedMultipleCredentials
case .notAllowedToHandleEncrypted:
Expand All @@ -447,7 +447,7 @@ extension RejectReason: FromGRPC {
case .runtimeFailure:
return .runtimeFailure
case let .scheduledSelfTransfer(v):
return .scheduledSelfTransfer(contents: .fromGRPC(v))
return try .scheduledSelfTransfer(contents: .fromGRPC(v))
case .serializationFailure:
return .serializationFailure
case .stakeOverMaximumThresholdForPool:
Expand Down Expand Up @@ -535,6 +535,6 @@ extension EncryptedAmountRemovedEvent: FromGRPC {
typealias GRPC = Concordium_V2_EncryptedAmountRemovedEvent

static func fromGRPC(_ g: GRPC) throws -> EncryptedAmountRemovedEvent {
.init(account: .fromGRPC(g.account), newAmount: g.newAmount.value, inputAmount: g.inputAmount.value, upToIndex: g.upToIndex)
try .init(account: .fromGRPC(g.account), newAmount: g.newAmount.value, inputAmount: g.inputAmount.value, upToIndex: g.upToIndex)
}
}
Loading
Loading