Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
70 changes: 30 additions & 40 deletions Examples/Schedule/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
// by this account and be signed by this key
client.setOperator(env.operatorAccountId, env.operatorKey)

let key = PrivateKey.generateEd25519()
let accountId = try await AccountCreateTransaction()
.keyWithoutAlias(.single(key.publicKey))
.execute(client)
.getReceipt(client)
.accountId!

// Generate a Ed25519 private, public key pair
let key1 = PrivateKey.generateEd25519()
let key2 = PrivateKey.generateEd25519()
Expand All @@ -23,62 +30,45 @@
print("private key 2 = \(key2)")
print("public key 2 = \(key2.publicKey)")

let newAccountId = try await AccountCreateTransaction()
.keyWithoutAlias(.keyList([.single(key1.publicKey), .single(key2.publicKey)]))
.initialBalance(.fromTinybars(1000))
var customFee = CustomFixedFee()
customFee.feeCollectorAccountId = accountId
customFee.amount = 10

let topicId = try await TopicCreateTransaction()
.feeScheduleKey(.single(key1.publicKey))
.addCustomFee(customFee)
.execute(client)
.getReceipt(client)
.accountId!
.topicId!

print("new account ID: \(newAccountId)")
print("new topic ID: \(topicId)")

let tx = TransferTransaction()
.hbarTransfer(newAccountId, -Hbar(1))
.hbarTransfer(env.operatorAccountId, Hbar(1))
var customFeeLimitFee = CustomFixedFee()
customFeeLimitFee.amount = 5
let customFeeLimit = CustomFeeLimit(payerId: env.operatorAccountId, customFees: [customFeeLimitFee])

let response =
try await tx
let response = try await TopicMessageSubmitTransaction()
.topicId(topicId)
.message("hello from hashgraph".data(using: .utf8)!)

Check notice on line 52 in Examples/Schedule/main.swift

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

Examples/Schedule/main.swift#L52

Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`
.addCustomFeeLimit(customFeeLimit)
.schedule()
.expirationTime(.now + .days(1))
.expirationTime(.now + .seconds(3))
.isWaitForExpiry(true)
.execute(client)

print("scheduled transaction ID = \(response.transactionId)")
let scheduledTransactionId = response.transactionId
print("scheduled transaction ID = \(scheduledTransactionId)")

let scheduleId = try await response.getReceipt(client).scheduleId!
print("schedule ID = \(scheduleId)")

let record = try await response.getRecord(client)
print("record = \(record)")

_ = try await ScheduleSignTransaction()
.scheduleId(scheduleId)
.freezeWith(client)
.sign(key1)
.execute(client)
.getReceipt(client)

let info = try await ScheduleInfoQuery()
.scheduleId(scheduleId)
.execute(client)

print("schedule info = \(info)")

_ = try await ScheduleSignTransaction()
.scheduleId(scheduleId)
.freezeWith(client)
.sign(key2)
.execute(client)
.getReceipt(client)

let transactionId = response.transactionId
_ = try await Task.sleep(nanoseconds: 1_000_000_000 * 6)

print("The following link should query the mirror node for the scheduled transaction:")
let scheduleInfo = try await ScheduleInfoQuery().scheduleId(scheduleId).execute(client)

let transactionIdString =
"\(transactionId.accountId)-\(transactionId.validStart.seconds)-\(transactionId.validStart.subSecondNanos)"
print("scheduleInfo = \(scheduleInfo)")

print("https://\(env.networkName).mirrornode.hedera.com/api/v1/transactions/\(transactionIdString)")
print("scheduled transaction receipt = \(try await TransactionReceiptQuery().transactionId(scheduledTransactionId).execute(client))")
}
}

Expand Down
1 change: 1 addition & 0 deletions Sources/Hiero/Schedule/ScheduleCreateTransaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ extension ScheduleCreateTransaction: ToProtobuf {
Proto_SchedulableTransactionBody.with { proto in
proto.data = scheduledTransaction.toSchedulableTransactionData()
proto.memo = scheduledTransaction.transaction.transactionMemo
proto.maxCustomFees = scheduledTransaction.transaction.customFeeLimits.compactMap { $0.toProtobuf() }

let transactionFee =
scheduledTransaction.transaction.maxTransactionFee
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public struct Proto_InternalCallContext: @unchecked Sendable {
}

///*
/// Results of executing EVM transaction.<br/>
/// Results of executing a EVM transaction.<br/>
public struct Proto_EvmTransactionResult: @unchecked Sendable {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
Expand Down Expand Up @@ -99,7 +99,8 @@ public struct Proto_EvmTransactionResult: @unchecked Sendable {
public var gasUsed: UInt64 = 0

///*
/// If not already externalized, the context of the internal call producing this result.
/// If not already externalized in a transaction body, the context of the
/// internal call producing this result.
public var internalCallContext: Proto_InternalCallContext {
get {return _internalCallContext ?? Proto_InternalCallContext()}
set {_internalCallContext = newValue}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,9 @@ public struct Com_Hedera_Hapi_Node_Addressbook_NodeUpdateTransactionBody: Sendab
/// This endpoint MUST use a valid port and SHALL be reachable over TLS.<br/>
/// This field MAY be omitted if the node does not support gRPC-Web access.<br/>
/// This field MUST be updated if the gRPC-Web endpoint changes.<br/>
/// This field SHALL enable frontend clients to avoid hard-coded proxy endpoints.
/// This field SHALL enable frontend clients to avoid hard-coded proxy endpoints.<br/>
/// This field MAY be set to `ServiceEndpoint.DEFAULT` to remove a previously-valid
/// web proxy.
public var grpcProxyEndpoint: Proto_ServiceEndpoint {
get {return _grpcProxyEndpoint ?? Proto_ServiceEndpoint()}
set {_grpcProxyEndpoint = newValue}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,10 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum, Swift.CaseIterable {
/// The GRPC proxy endpoint is set in the NodeCreate or NodeUpdate transaction,
/// which the network does not support.
case grpcWebProxyNotSupported // = 399

///*
/// An NFT transfers list referenced a token type other than NON_FUNGIBLE_UNIQUE.
case nftTransfersOnlyAllowedForNonFungibleUnique // = 400
case UNRECOGNIZED(Int)

public init() {
Expand Down Expand Up @@ -1912,6 +1916,7 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum, Swift.CaseIterable {
case 397: self = .throttleGroupLcmOverflow
case 398: self = .airdropContainsMultipleSendersForAToken
case 399: self = .grpcWebProxyNotSupported
case 400: self = .nftTransfersOnlyAllowedForNonFungibleUnique
default: self = .UNRECOGNIZED(rawValue)
}
}
Expand Down Expand Up @@ -2276,6 +2281,7 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum, Swift.CaseIterable {
case .throttleGroupLcmOverflow: return 397
case .airdropContainsMultipleSendersForAToken: return 398
case .grpcWebProxyNotSupported: return 399
case .nftTransfersOnlyAllowedForNonFungibleUnique: return 400
case .UNRECOGNIZED(let i): return i
}
}
Expand Down Expand Up @@ -2640,6 +2646,7 @@ public enum Proto_ResponseCodeEnum: SwiftProtobuf.Enum, Swift.CaseIterable {
.throttleGroupLcmOverflow,
.airdropContainsMultipleSendersForAToken,
.grpcWebProxyNotSupported,
.nftTransfersOnlyAllowedForNonFungibleUnique,
]

}
Expand Down Expand Up @@ -3006,5 +3013,6 @@ extension Proto_ResponseCodeEnum: SwiftProtobuf._ProtoNameProviding {
397: .same(proto: "THROTTLE_GROUP_LCM_OVERFLOW"),
398: .same(proto: "AIRDROP_CONTAINS_MULTIPLE_SENDERS_FOR_A_TOKEN"),
399: .same(proto: "GRPC_WEB_PROXY_NOT_SUPPORTED"),
400: .same(proto: "NFT_TRANSFERS_ONLY_ALLOWED_FOR_NON_FUNGIBLE_UNIQUE"),
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,17 @@ public struct Proto_SchedulableTransactionBody: @unchecked Sendable {
set {_uniqueStorage()._data = .tokenAirdrop(newValue)}
}

///*
/// A list of maximum custom fees that the users are willing to pay.
/// <p>
/// This field is OPTIONAL.<br/>
/// If left empty, the users are accepting to pay any custom fee.<br/>
/// If used with a transaction type that does not support custom fee limits, the transaction will fail.
public var maxCustomFees: [Proto_CustomFeeLimit] {
get {return _storage._maxCustomFees}
set {_uniqueStorage()._maxCustomFees = newValue}
}

public var unknownFields = SwiftProtobuf.UnknownStorage()

public enum OneOf_Data: Equatable, Sendable {
Expand Down Expand Up @@ -878,12 +889,14 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf
46: .same(proto: "tokenCancelAirdrop"),
47: .same(proto: "tokenClaimAirdrop"),
48: .same(proto: "tokenAirdrop"),
1001: .standard(proto: "max_custom_fees"),
]

fileprivate class _StorageClass {
var _transactionFee: UInt64 = 0
var _memo: String = String()
var _data: Proto_SchedulableTransactionBody.OneOf_Data?
var _maxCustomFees: [Proto_CustomFeeLimit] = []

#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
Expand All @@ -901,6 +914,7 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf
_transactionFee = source._transactionFee
_memo = source._memo
_data = source._data
_maxCustomFees = source._maxCustomFees
}
}

Expand Down Expand Up @@ -1519,6 +1533,7 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf
_storage._data = .tokenAirdrop(v)
}
}()
case 1001: try { try decoder.decodeRepeatedMessageField(value: &_storage._maxCustomFees) }()
default: break
}
}
Expand Down Expand Up @@ -1724,6 +1739,9 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf
}()
case nil: break
}
if !_storage._maxCustomFees.isEmpty {
try visitor.visitRepeatedMessageField(value: _storage._maxCustomFees, fieldNumber: 1001)
}
}
try unknownFields.traverse(visitor: &visitor)
}
Expand All @@ -1736,6 +1754,7 @@ extension Proto_SchedulableTransactionBody: SwiftProtobuf.Message, SwiftProtobuf
if _storage._transactionFee != rhs_storage._transactionFee {return false}
if _storage._memo != rhs_storage._memo {return false}
if _storage._data != rhs_storage._data {return false}
if _storage._maxCustomFees != rhs_storage._maxCustomFees {return false}
return true
}
if !storagesAreEqual {return false}
Expand Down
5 changes: 3 additions & 2 deletions Sources/HieroProtobufs/Protos/services/contract_types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ message InternalCallContext {
}

/**
* Results of executing EVM transaction.<br/>
* Results of executing a EVM transaction.<br/>
*/
message EvmTransactionResult {
/**
Expand Down Expand Up @@ -73,7 +73,8 @@ message EvmTransactionResult {
uint64 gas_used = 5;

/**
* If not already externalized, the context of the internal call producing this result.
* If not already externalized in a transaction body, the context of the
* internal call producing this result.
*/
InternalCallContext internal_call_context = 6;
}
Expand Down
4 changes: 3 additions & 1 deletion Sources/HieroProtobufs/Protos/services/node_update.proto
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@ message NodeUpdateTransactionBody {
* This endpoint MUST use a valid port and SHALL be reachable over TLS.<br/>
* This field MAY be omitted if the node does not support gRPC-Web access.<br/>
* This field MUST be updated if the gRPC-Web endpoint changes.<br/>
* This field SHALL enable frontend clients to avoid hard-coded proxy endpoints.
* This field SHALL enable frontend clients to avoid hard-coded proxy endpoints.<br/>
* This field MAY be set to `ServiceEndpoint.DEFAULT` to remove a previously-valid
* web proxy.
*/
proto.ServiceEndpoint grpc_proxy_endpoint = 10;
}
5 changes: 5 additions & 0 deletions Sources/HieroProtobufs/Protos/services/response_code.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1760,4 +1760,9 @@ enum ResponseCodeEnum {
* which the network does not support.
*/
GRPC_WEB_PROXY_NOT_SUPPORTED = 399;

/**
* An NFT transfers list referenced a token type other than NON_FUNGIBLE_UNIQUE.
*/
NFT_TRANSFERS_ONLY_ALLOWED_FOR_NON_FUNGIBLE_UNIQUE = 400;
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import "services/token_airdrop.proto";

import "services/schedule_delete.proto";
import "services/util_prng.proto";
import "services/custom_fees.proto";

import "services/node_create.proto";
import "services/node_update.proto";
Expand Down Expand Up @@ -403,4 +404,13 @@ message SchedulableTransactionBody {
*/
TokenAirdropTransactionBody tokenAirdrop = 48;
}

/**
* A list of maximum custom fees that the users are willing to pay.
* <p>
* This field is OPTIONAL.<br/>
* If left empty, the users are accepting to pay any custom fee.<br/>
* If used with a transaction type that does not support custom fee limits, the transaction will fail.
*/
repeated CustomFeeLimit max_custom_fees = 1001;
}
26 changes: 25 additions & 1 deletion Tests/HieroTests/TopicMessageSubmitTransactionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal final class TopicMessageSubmitTransactionTests: XCTestCase {
internal func testSerialize() throws {
let tx = try Self.makeTransaction().makeProtoBody()

assertSnapshot(matching: tx, as: .description)
assertSnapshot(of: tx, as: .description)
}

internal func testToFromBytes() throws {
Expand Down Expand Up @@ -128,4 +128,28 @@ internal final class TopicMessageSubmitTransactionTests: XCTestCase {

XCTAssertEqual(tx.customFeeLimits, [customFeeLimitToAdd])
}

internal func testScheduledCustomFeeLimits() throws {
let payerId = AccountId(3)
let amount: UInt64 = 4
let tokenId = TokenId(3)
let customFeeLimitToAdd = CustomFeeLimit(
payerId: payerId,
customFees: [
CustomFixedFee(amount, nil, tokenId)
])

let tx = TopicMessageSubmitTransaction()
.addCustomFeeLimit(customFeeLimitToAdd)
.schedule()
.toProtobuf()

XCTAssertEqual(tx.scheduledTransactionBody.maxCustomFees.count, 1)
XCTAssertEqual(tx.scheduledTransactionBody.maxCustomFees[0].accountID.accountNum, Int64(payerId.num))
XCTAssertEqual(tx.scheduledTransactionBody.maxCustomFees[0].fees.count, 1)
XCTAssertEqual(tx.scheduledTransactionBody.maxCustomFees[0].fees[0].amount, Int64(amount))
XCTAssertEqual(
tx.scheduledTransactionBody.maxCustomFees[0].fees[0].denominatingTokenID.tokenNum, Int64(tokenId.num))

}
}
2 changes: 1 addition & 1 deletion protobufs
Submodule protobufs updated 1445 files
Loading