Skip to content

Commit 92ee2a2

Browse files
authored
feat: Implement JSON-RPC endpoint for AccountCreateTransaction
1 parent e15c798 commit 92ee2a2

File tree

7 files changed

+344
-214
lines changed

7 files changed

+344
-214
lines changed

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/Hedera/Account/AccountCreateTransaction.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ extension AccountCreateTransaction: ToProtobuf {
283283
internal func toProtobuf() -> Protobuf {
284284
.with { proto in
285285
key?.toProtobufInto(&proto.key)
286-
proto.initialBalance = UInt64(initialBalance.toTinybars())
286+
proto.initialBalance = UInt64(truncatingIfNeeded: initialBalance.toTinybars())
287287
proto.receiverSigRequired = receiverSignatureRequired
288288
autoRenewPeriod?.toProtobufInto(&proto.autoRenewPeriod)
289289
// autoRenewAccountId?.toProtobufInto(&proto.autoRenewAccount)
@@ -295,7 +295,7 @@ extension AccountCreateTransaction: ToProtobuf {
295295
}
296296

297297
if let stakedNodeId = stakedNodeId {
298-
proto.stakedNodeID = Int64(stakedNodeId)
298+
proto.stakedNodeID = Int64(truncatingIfNeeded: stakedNodeId)
299299
}
300300

301301
if let stakedAccountId = stakedAccountId {

Sources/Hedera/Duration.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ extension Duration: ProtobufCodable {
3333
}
3434

3535
internal func toProtobuf() -> Protobuf {
36-
.with { proto in proto.seconds = Int64(seconds) }
36+
.with { proto in proto.seconds = Int64(truncatingIfNeeded: seconds) }
3737
}
3838
}

Sources/HederaTCK/JSONHelper.swift

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* ‌
3+
* Hedera Swift SDK
4+
* ​
5+
* Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC
6+
* ​
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* ‍
19+
*/
20+
internal func getJson<T>(_ json: JSONObject, _ paramName: String, _ functionName: String) throws
21+
-> T
22+
{
23+
if T.self == String.self {
24+
guard let val = json.stringValue else {
25+
throw JSONError.invalidParams("\(functionName): \(paramName) MUST be a string.")
26+
}
27+
return val as! T
28+
}
29+
if T.self == Int.self || T.self == Int32.self || T.self == UInt32.self || T.self == Int64.self
30+
|| T.self == UInt64.self
31+
{
32+
guard let val = json.intValue else {
33+
throw JSONError.invalidParams("\(functionName): \(paramName) MUST be an integer.")
34+
}
35+
return val as! T
36+
}
37+
if T.self == Double.self || T.self == Float.self {
38+
guard let val = json.doubleValue else {
39+
throw JSONError.invalidParams("\(functionName): \(paramName) MUST be a double.")
40+
}
41+
return val as! T
42+
}
43+
if T.self == Bool.self {
44+
guard let val = json.boolValue else {
45+
throw JSONError.invalidParams("\(functionName): \(paramName) MUST be a boolean.")
46+
}
47+
return val as! T
48+
}
49+
if T.self == [JSONObject].self {
50+
guard let val = json.listValue else {
51+
throw JSONError.invalidParams("\(functionName): \(paramName) MUST be a list.")
52+
}
53+
return val as! T
54+
}
55+
if T.self == [String: JSONObject].self {
56+
guard let val = json.dictValue else {
57+
throw JSONError.invalidParams("\(functionName): \(paramName) MUST be a dictionary.")
58+
}
59+
return val as! T
60+
}
61+
62+
throw JSONError.invalidParams("\(functionName): \(paramName) is NOT a valid type.")
63+
}
64+
65+
internal func getParam(_ json: JSONObject?, _ paramName: String, _ functionName: String) throws -> JSONObject {
66+
return try json ?? { throw JSONError.invalidParams("\(functionName): \(paramName) MUST be provided.") }()
67+
}
68+
69+
internal func getOptionalJsonParameter<T>(
70+
_ name: String, _ parameters: [String: JSONObject], _ functionName: String
71+
) throws -> T? {
72+
guard let param = parameters[name] else {
73+
return nil
74+
}
75+
return try getJson(param, name, functionName) as T
76+
}
77+
78+
internal func getRequiredJsonParameter<T>(
79+
_ name: String, _ parameters: [String: JSONObject], _ functionName: String
80+
) throws -> T {
81+
return try getJson(getParam(parameters[name], name, functionName), name, functionName)
82+
}

Sources/HederaTCK/JSONRPCTypes.swift

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,26 @@ import Vapor
2424
private let jsonRpcVersion = "2.0"
2525

2626
internal struct JSONRequest: Decodable {
27-
let jsonrpc: String
28-
var id: Int
29-
var method: String
30-
var params: JSONObject?
27+
internal let jsonrpc: String
28+
internal var id: Int
29+
internal var method: String
30+
internal var params: JSONObject?
3131

32-
enum CodingKeys: String, CodingKey {
32+
private enum CodingKeys: String, CodingKey {
3333
case jsonrpc
3434
case id
3535
case method
3636
case params
3737
}
3838

39-
init(id: Int, method: String, params: JSONObject) {
39+
internal init(id: Int, method: String, params: JSONObject) {
4040
self.jsonrpc = jsonRpcVersion
4141
self.id = id
4242
self.method = method
4343
self.params = params
4444
}
4545

46-
init(from decoder: Decoder) throws {
46+
internal init(from decoder: Decoder) throws {
4747
let container = try decoder.container(keyedBy: CodingKeys.self)
4848

4949
guard let jsonrpc = try container.decodeIfPresent(String.self, forKey: .jsonrpc) else {
@@ -72,22 +72,36 @@ internal struct JSONRequest: Decodable {
7272
self.params = nil
7373
}
7474
}
75+
76+
internal func toDict() -> [String: JSONObject] {
77+
var dict = [
78+
"jsonrpc": JSONObject.string(jsonRpcVersion),
79+
"id": JSONObject.int(Int64(self.id)),
80+
"method": JSONObject.string(self.method),
81+
]
82+
83+
if let params = self.params {
84+
dict["params"] = params
85+
}
86+
87+
return dict
88+
}
7589
}
7690

7791
internal struct JSONResponse: Encodable {
78-
let jsonrpc: String
79-
var id: Int?
80-
var result: JSONObject?
81-
var error: JSONError?
92+
internal let jsonrpc: String
93+
internal var id: Int?
94+
internal var result: JSONObject?
95+
internal var error: JSONError?
8296

83-
init(id: Int, result: JSONObject) {
97+
internal init(id: Int, result: JSONObject) {
8498
self.jsonrpc = jsonRpcVersion
8599
self.id = id
86100
self.result = result
87101
self.error = nil
88102
}
89103

90-
init(id: Int?, error: JSONError) {
104+
internal init(id: Int?, error: JSONError) {
91105
self.jsonrpc = jsonRpcVersion
92106
self.id = id
93107
self.result = nil
@@ -103,13 +117,13 @@ internal enum JSONError: Encodable, Error {
103117
case internalError(String, JSONObject? = nil)
104118
case parseError(String, JSONObject? = nil)
105119

106-
enum CodingKeys: String, CodingKey {
120+
private enum CodingKeys: String, CodingKey {
107121
case code
108122
case message
109123
case data
110124
}
111125

112-
var code: Int {
126+
internal var code: Int {
113127
switch self {
114128
case .hederaError: return -32001
115129
case .invalidRequest: return -32600
@@ -120,7 +134,7 @@ internal enum JSONError: Encodable, Error {
120134
}
121135
}
122136

123-
var message: String {
137+
internal var message: String {
124138
switch self {
125139
case .hederaError(let message, _),
126140
.invalidRequest(let message, _),
@@ -132,7 +146,7 @@ internal enum JSONError: Encodable, Error {
132146
}
133147
}
134148

135-
var data: JSONObject? {
149+
internal var data: JSONObject? {
136150
switch self {
137151
case .hederaError(_, let data),
138152
.invalidRequest(_, let data),
@@ -144,7 +158,7 @@ internal enum JSONError: Encodable, Error {
144158
}
145159
}
146160

147-
func encode(to encoder: Encoder) throws {
161+
internal func encode(to encoder: Encoder) throws {
148162
var container = encoder.container(keyedBy: CodingKeys.self)
149163
try container.encode(code, forKey: .code)
150164
try container.encode(message, forKey: .message)
@@ -153,58 +167,57 @@ internal enum JSONError: Encodable, Error {
153167
}
154168

155169
internal enum JSONObject: Codable {
156-
case none
157170
case string(String)
158-
case integer(Int)
171+
case int(Int64)
159172
case double(Double)
160173
case bool(Bool)
161174
case list([JSONObject])
162175
case dictionary([String: JSONObject])
163176

164-
var stringValue: String? {
177+
internal var stringValue: String? {
165178
if case .string(let value) = self {
166179
return value
167180
}
168181
return nil
169182
}
170-
var intValue: Int? {
171-
if case .integer(let value) = self {
183+
internal var intValue: Int64? {
184+
if case .int(let value) = self {
172185
return value
173186
}
174187
return nil
175188
}
176-
var doubleValue: Double? {
189+
internal var doubleValue: Double? {
177190
if case .double(let value) = self {
178191
return value
179192
}
180193
return nil
181194
}
182-
var boolValue: Bool? {
195+
internal var boolValue: Bool? {
183196
if case .bool(let value) = self {
184197
return value
185198
}
186199
return nil
187200
}
188-
var listValue: [JSONObject]? {
201+
internal var listValue: [JSONObject]? {
189202
if case .list(let value) = self {
190203
return value
191204
}
192205
return nil
193206
}
194-
var dictValue: [String: JSONObject]? {
207+
internal var dictValue: [String: JSONObject]? {
195208
if case .dictionary(let value) = self {
196209
return value
197210
}
198211
return nil
199212
}
200213

201-
init(from decoder: Decoder) throws {
214+
internal init(from decoder: Decoder) throws {
202215
let container = try decoder.singleValueContainer()
203216

204217
if let value = try? container.decode(String.self) {
205218
self = .string(value)
206-
} else if let value = try? container.decode(Int.self) {
207-
self = .integer(value)
219+
} else if let value = try? container.decode(Int64.self) {
220+
self = .int(value)
208221
} else if let value = try? container.decode(Double.self) {
209222
self = .double(value)
210223
} else if let value = try? container.decode(Bool.self) {
@@ -214,19 +227,17 @@ internal enum JSONObject: Codable {
214227
} else if let value = try? container.decode([String: JSONObject].self) {
215228
self = .dictionary(value)
216229
} else {
217-
self = .none
230+
throw JSONError.invalidParams("param type not recognized")
218231
}
219232
}
220233

221-
func encode(to encoder: Encoder) throws {
234+
internal func encode(to encoder: Encoder) throws {
222235
var container = encoder.singleValueContainer()
223236

224237
switch self {
225-
case .none:
226-
break
227238
case .string(let value):
228239
try container.encode(value)
229-
case .integer(let value):
240+
case .int(let value):
230241
try container.encode(value)
231242
case .double(let value):
232243
try container.encode(value)

0 commit comments

Comments
 (0)