Skip to content

Commit

Permalink
feat(HIP-540): change or remove existing keys from tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
RickyLB authored Jun 20, 2024
1 parent 47ee636 commit 0a31d43
Show file tree
Hide file tree
Showing 52 changed files with 3,645 additions and 231 deletions.
166 changes: 166 additions & 0 deletions Examples/ModifyTokenKeys/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* ‌
* Hedera Swift SDK
*
* Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

import Foundation
import Hedera
import SwiftDotenv

@main
internal enum Program {
internal static func main() async throws {
let env = try Dotenv.load()
let client = try Client.forName(env.networkName)

// Defaults the operator account ID and key such that all generated transactions will be paid for
// by this account and be signed by this key
client.setOperator(env.operatorAccountId, env.operatorKey)

// Generate a higher-privileged key.
let adminKey = PrivateKey.generateEd25519()

// Generate the lower-privileged keys that will be modified.
// Note: Lower-privileged keys are Wipe, Supply, and updated Supply key..
let supplyKey = PrivateKey.generateEd25519()
let wipeKey = PrivateKey.generateEd25519()
let newSupplyKey = PrivateKey.generateEd25519()

let unusableKey = try PublicKey.fromStringEd25519(
"0x0000000000000000000000000000000000000000000000000000000000000000")

// Create an NFT token with admin, wipe, and supply key.
let tokenId = try await TokenCreateTransaction()
.name("Example NFT")
.symbol("ENFT")
.tokenType(TokenType.nonFungibleUnique)
.treasuryAccountId(env.operatorAccountId)
.adminKey(.single(adminKey.publicKey))
.wipeKey(.single(wipeKey.publicKey))
.supplyKey(.single(supplyKey.publicKey))
.expirationTime(Timestamp.now + .minutes(5))
.freezeWith(client)
.sign(adminKey)
.execute(client)
.getReceipt(client)
.tokenId!

let tokenInfo = try await TokenInfoQuery()
.tokenId(tokenId)
.execute(client)

print("Admin Key: \(tokenInfo.adminKey!)")
print("Wipe Key: \(tokenInfo.wipeKey!)")
print("Supply Key: \(tokenInfo.supplyKey!)")

print("------------------------------------")
print("Removing Wipe Key...")

// Remove the wipe key with empty Keylist, signing with the admin key.
let _ = try await TokenUpdateTransaction()
.tokenId(tokenId)
.wipeKey(.keyList([]))
.keyVerificationMode(TokenKeyValidation.fullValidation)
.freezeWith(client)
.sign(adminKey)
.execute(client)
.getReceipt(client)

let tokenInfoAfterWipeKeyUpdate = try await TokenInfoQuery()
.tokenId(tokenId)
.execute(client)

print("Wipe Key (after removal): \(String(describing: tokenInfoAfterWipeKeyUpdate.wipeKey))")
print("------------------------------------")
print("Removing Admin Key...")

// Remove the admin key with empty Keylist, signing with the admin key.
let _ = try await TokenUpdateTransaction()
.tokenId(tokenId)
.adminKey(.keyList([]))
.keyVerificationMode(TokenKeyValidation.noValidation)
.freezeWith(client)
.sign(adminKey)
.execute(client)
.getReceipt(client)

let tokenInfoAfterAdminKeyUpdate = try await TokenInfoQuery()
.tokenId(tokenId)
.execute(client)

print("Admin Key (after removal): \(String(describing:tokenInfoAfterAdminKeyUpdate.adminKey))")

print("------------------------------------")
print("Update Supply Key...")

// Update the supply key with a new key, signing with the old supply key and the new supply key.
let _ = try await TokenUpdateTransaction()
.tokenId(tokenId)
.supplyKey(.single(newSupplyKey.publicKey))
.keyVerificationMode(TokenKeyValidation.fullValidation)
.freezeWith(client)
.sign(supplyKey)
.sign(newSupplyKey)
.execute(client)
.getReceipt(client)

let tokenInfoAfterSupplyKeyUpdate = try await TokenInfoQuery()
.tokenId(tokenId)
.execute(client)

print("Supply Key (after update): \(String(describing: tokenInfoAfterSupplyKeyUpdate.supplyKey))")

print("------------------------------------")
print("Removing Supply Key...")

// Remove the supply key with unusable key, signing with the new supply key.
let _ = try await TokenUpdateTransaction()
.tokenId(tokenId)
.supplyKey(.single(unusableKey))
.keyVerificationMode(TokenKeyValidation.noValidation)
.freezeWith(client)
.sign(newSupplyKey)
.execute(client)
.getReceipt(client)

let tokenInfoAfterSupplyKeyRemoval = try await TokenInfoQuery()
.tokenId(tokenId)
.execute(client)

print("Supply Key (after removal): \(String(describing: tokenInfoAfterSupplyKeyRemoval.supplyKey))")
}
}

extension Environment {
/// Account ID for the operator to use in this example.
internal var operatorAccountId: AccountId {
AccountId(self["OPERATOR_ID"]!.stringValue)!
}

/// Private key for the operator to use in this example.
internal var operatorKey: PrivateKey {
PrivateKey(self["OPERATOR_KEY"]!.stringValue)!
}

/// The name of the hedera network this example should be ran against.
///
/// Testnet by default.
internal var networkName: String {
self["HEDERA_NETWORK"]?.stringValue ?? "testnet"
}
}
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ let exampleTargets = [
"GetAddressBook",
"GetExchangeRates",
"GetFileContents",
"ModifyTokenKeys",
"MultiAppTransfer",
"MultiSigOffline",
"Prng",
Expand Down Expand Up @@ -130,7 +131,7 @@ let package = Package(
// .unsafeFlags(["-Xfrontend", "-warn-concurrency", "-Xfrontend", "-enable-actor-data-race-checks"])
// ]
),
.target(
.executableTarget(
name: "HederaTCK",
dependencies: [
"Hedera",
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@ protoc
protoc-gen-swift (from https://github.com/apple/swift-protobuf)
protoc-gen-grpc-swift (from https://github.com/grpc/grpc-swift)

### Fetch Submodule (Hedera-Protobufs)
Update [\protobuf](https://github.com/hashgraph/hedera-protobufs) submodule to latest changes.
```bash
git submodule update --recursive --remote
```

### Generate services

```bash
# cwd: `$REPO`
protoc --swift_opt=Visibility=Public --swift_opt=FileNaming=PathToUnderscores --swift_out=./Sources/HederaProtobufs/Services --proto_path=./protobufs/services protobufs/services/**.proto
Expand Down
4 changes: 3 additions & 1 deletion Sources/Hedera/AnyTransaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,13 @@ extension ServicesTransactionDataList: TryFromProtobuf {
case .scheduleSign(let data): value = .scheduleSign([data])
case .utilPrng(let data): value = .prng([data])
case .tokenUpdateNfts(let data): value = .tokenUpdateNfts([data])

case .cryptoAddLiveHash: throw HError.fromProtobuf("Unsupported transaction `AddLiveHashTransaction`")
case .cryptoDeleteLiveHash: throw HError.fromProtobuf("Unsupported transaction `DeleteLiveHashTransaction`")
case .uncheckedSubmit: throw HError.fromProtobuf("Unsupported transaction `UncheckedSubmitTransaction`")
case .nodeStakeUpdate: throw HError.fromProtobuf("Unsupported transaction `NodeStakeUpdateTransaction`")
case .nodeDelete: throw HError.fromProtobuf("Unsupported transaction `NodeDeleteTransaction`")
case .nodeCreate: throw HError.fromProtobuf("Unsupported transaction `NodeCreateTransaction`")
case .nodeUpdate: throw HError.fromProtobuf("Unsupported transaction `NodeUpdateTransaction`")
}

for transaction in iter {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Hedera/FeeSchedule/FeeDataType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ extension FeeDataType: TryProtobufCodable {
case .tokenFungibleCommonWithCustomFees: self = .tokenFungibleCommonWithCustomFees
case .tokenNonFungibleUniqueWithCustomFees: self = .tokenNonFungibleUniqueWithCustomFees
case .scheduleCreateContractCall: self = .scheduleCreateContractCall
case .unrecognized(let code):
case .UNRECOGNIZED(let code):
throw HError.fromProtobuf("unrecognized FeeDataType `\(code)`")
}
}
Expand Down
26 changes: 23 additions & 3 deletions Sources/Hedera/FeeSchedule/RequestType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,18 @@ public enum RequestType {
/// Update a Non-Fungible token.
case tokenUpdateNfts

/// Create a node
case nodeCreate

/// Update a node
case nodeUpdate

/// Delete a node
case nodeDelete

/// Get the info for a node
case nodeGetInfo

// this literally can't be smaller.
// swiftlint:disable:next function_body_length
internal init?(protobuf proto: Proto_HederaFunctionality) throws {
Expand Down Expand Up @@ -324,10 +336,14 @@ public enum RequestType {
case .ethereumTransaction: self = .ethereumTransaction
case .nodeStakeUpdate: self = .nodeStakeUpdate
case .utilPrng: self = .utilPrng
case .transactionGetFastRecord: self = .tokenUpdateNfts

case .transactionGetFastRecord: self = .transactionGetFastRecord
case .tokenUpdateNfts: self = .tokenUpdateNfts
case .unrecognized(let code):
case .nodeCreate: self = .nodeCreate
case .nodeDelete: self = .nodeDelete
case .nodeUpdate: self = .nodeUpdate
case .nodeGetInfo: self = .nodeGetInfo

case .UNRECOGNIZED(let code):
throw HError.fromProtobuf("unrecognized RequestType: `\(code)`")
}
}
Expand Down Expand Up @@ -408,6 +424,10 @@ public enum RequestType {
case .utilPrng: return .utilPrng
case .transactionGetFastRecord: return .transactionGetFastRecord
case .tokenUpdateNfts: return .tokenUpdateNfts
case .nodeCreate: return .nodeCreate
case .nodeUpdate: return .nodeUpdate
case .nodeDelete: return .nodeDelete
case .nodeGetInfo: return .nodeGetInfo
}
}
}
2 changes: 1 addition & 1 deletion Sources/Hedera/FreezeType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ extension FreezeType: TryProtobufCodable {
case .freezeUpgrade: self = .freezeUpgrade
case .freezeAbort: self = .freezeAbort
case .telemetryUpgrade: self = .telemetryUpgrade
case .unrecognized(let value): throw HError.fromProtobuf("unrecognized FreezeType: `\(value)`")
case .UNRECOGNIZED(let value): throw HError.fromProtobuf("unrecognized FreezeType: `\(value)`")
}
}

Expand Down
3 changes: 3 additions & 0 deletions Sources/Hedera/Schedule/ScheduleInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ public struct ScheduleInfo: Sendable {
case .scheduleDelete(let data): proto.data = .scheduleDelete(data)
case .utilPrng(let data): proto.data = .utilPrng(data)
case .tokenUpdateNfts(let data): proto.data = .tokenUpdateNfts(data)
case .nodeCreate(let data): proto.data = .nodeCreate(data)
case .nodeUpdate(let data): proto.data = .nodeUpdate(data)
case .nodeDelete(let data): proto.data = .nodeDelete(data)
case nil: break
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/Hedera/Token/TokenInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ extension TokenInfo: TryProtobufCodable {
defaultFreezeStatus = true
case .unfrozen:
defaultFreezeStatus = false
case .unrecognized(let value):
case .UNRECOGNIZED(let value):
throw HError.fromProtobuf("Unrecognized defaultFreezeStatus: `\(value)`")
}

Expand All @@ -157,7 +157,7 @@ extension TokenInfo: TryProtobufCodable {
defaultKycStatus = true
case .revoked:
defaultKycStatus = false
case .unrecognized(let value):
case .UNRECOGNIZED(let value):
throw HError.fromProtobuf("Unrecognized defaultKycStatus: `\(value)`")
}

Expand All @@ -175,7 +175,7 @@ extension TokenInfo: TryProtobufCodable {
pauseStatus = true
case .unpaused:
pauseStatus = false
case .unrecognized(let value):
case .UNRECOGNIZED(let value):
throw HError.fromProtobuf("Unrecognized pauseStatus: `\(value)`")
}

Expand Down
54 changes: 54 additions & 0 deletions Sources/Hedera/Token/TokenKeyValidation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* ‌
* Hedera Swift SDK
* ​
* Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC
* ​
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ‍
*/

import Foundation
import HederaProtobufs

public enum TokenKeyValidation {
/// Currently the default behaviour. It will perform all token key validations.
case fullValidation
/// Perform no validations at all for all passed token keys.
case noValidation
/// The passed token key is not recognized.
case unrecognized(Int)
}

extension TokenKeyValidation: TryFromProtobuf {
internal typealias Protobuf = Proto_TokenKeyValidation

internal init(protobuf proto: Protobuf) throws {
switch proto {
case .fullValidation: self = .fullValidation
case .noValidation: self = .noValidation
case .UNRECOGNIZED(let value): self = .unrecognized(value)
}
}

func toProtobuf() -> Protobuf {
switch self {
case .fullValidation:
return .fullValidation
case .noValidation:
return .noValidation
case .unrecognized(let value):
return .UNRECOGNIZED(value)
}
}
}
2 changes: 1 addition & 1 deletion Sources/Hedera/Token/TokenSupplyType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extension TokenSupplyType: TryProtobufCodable {
self = .infinite
case .finite:
self = .finite
case .unrecognized(let value):
case .UNRECOGNIZED(let value):
throw HError.fromProtobuf("unrecognized TokenSupplyType: `\(value)`")
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Hedera/Token/TokenType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ extension TokenType: TryProtobufCodable {
switch proto {
case .fungibleCommon: self = .fungibleCommon
case .nonFungibleUnique: self = .nonFungibleUnique
case .unrecognized(let value):
case .UNRECOGNIZED(let value):
throw HError.fromProtobuf("unrecognized token type \(value)")
}
}
Expand Down
Loading

0 comments on commit 0a31d43

Please sign in to comment.