-
Notifications
You must be signed in to change notification settings - Fork 9
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
IOS-7779 Add TransactionBuilder #817
Changes from all commits
7516e93
bb770e1
b81a6ce
43be0dc
bf272b3
c43e5b0
f897f62
503be34
69202d6
66bba5b
490d283
bc59262
1462f26
e8b538f
e0b4aa8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// FilecoinFeeParameters.swift | ||
// BlockchainSdk | ||
// | ||
// Created by Aleksei Muraveinik on 30.08.24. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import BigInt | ||
|
||
struct FilecoinFeeParameters: FeeParameters { | ||
let gasUnitPrice: BigUInt | ||
let gasLimit: Int64 | ||
let gasPremium: BigUInt | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// | ||
// FilecoinTransactionBuilder.swift | ||
// BlockchainSdk | ||
// | ||
// Created by Aleksei Muraveinik on 29.08.24. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import TangemSdk | ||
import WalletCore | ||
|
||
enum FilecoinTransactionBuilderError: Error { | ||
case filecoinFeeParametersNotFound | ||
case failedToConvertAmountToBigUInt | ||
case failedToGetDataFromJSON | ||
} | ||
|
||
final class FilecoinTransactionBuilder { | ||
private let wallet: Wallet | ||
|
||
init(wallet: Wallet) { | ||
self.wallet = wallet | ||
} | ||
m3g0byt3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
func buildForSign(transaction: Transaction, nonce: UInt64) throws -> Data { | ||
guard let feeParameters = transaction.fee.parameters as? FilecoinFeeParameters else { | ||
throw FilecoinTransactionBuilderError.filecoinFeeParametersNotFound | ||
} | ||
|
||
let input = try makeSigningInput(transaction: transaction, nonce: nonce, feeParameters: feeParameters) | ||
let txInputData = try input.serializedData() | ||
|
||
let preImageHashes = TransactionCompiler.preImageHashes(coinType: .filecoin, txInputData: txInputData) | ||
let preSigningOutput = try TxCompilerPreSigningOutput(serializedData: preImageHashes) | ||
|
||
return preSigningOutput.dataHash | ||
} | ||
|
||
func buildForSend( | ||
transaction: Transaction, | ||
nonce: UInt64, | ||
signatureInfo: SignatureInfo | ||
) throws -> FilecoinSignedTransactionBody { | ||
guard let feeParameters = transaction.fee.parameters as? FilecoinFeeParameters else { | ||
throw FilecoinTransactionBuilderError.filecoinFeeParametersNotFound | ||
} | ||
m3g0byt3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
let signatures = DataVector() | ||
signatures.add(data: signatureInfo.signature) | ||
|
||
let publicKeys = DataVector() | ||
publicKeys.add(data: try Secp256k1Key(with: signatureInfo.publicKey).decompress()) | ||
|
||
let input = try makeSigningInput(transaction: transaction, nonce: nonce, feeParameters: feeParameters) | ||
let txInputData = try input.serializedData() | ||
|
||
let compiledWithSignatures = TransactionCompiler.compileWithSignatures( | ||
coinType: .filecoin, | ||
txInputData: txInputData, | ||
signatures: signatures, | ||
publicKeys: publicKeys | ||
) | ||
|
||
let signingOutput = try FilecoinSigningOutput(serializedData: compiledWithSignatures) | ||
|
||
guard let jsonData = signingOutput.json.data(using: .utf8) else { | ||
throw FilecoinTransactionBuilderError.failedToGetDataFromJSON | ||
} | ||
|
||
return try JSONDecoder().decode(FilecoinSignedTransactionBody.self, from: jsonData) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А там в API прям json будет уходить? обычно просто длинная hex строка There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
private func makeSigningInput( | ||
transaction: Transaction, | ||
nonce: UInt64, | ||
feeParameters: FilecoinFeeParameters | ||
) throws -> FilecoinSigningInput { | ||
guard let value = transaction.amount.bigUIntValue else { | ||
throw FilecoinTransactionBuilderError.failedToConvertAmountToBigUInt | ||
} | ||
|
||
return try FilecoinSigningInput.with { input in | ||
input.to = transaction.destinationAddress | ||
input.nonce = nonce | ||
|
||
input.value = value.serialize() | ||
|
||
input.gasFeeCap = feeParameters.gasUnitPrice.serialize() | ||
input.gasLimit = feeParameters.gasLimit | ||
input.gasPremium = feeParameters.gasPremium.serialize() | ||
|
||
input.publicKey = try Secp256k1Key(with: wallet.publicKey.blockchainKey).decompress() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Лучше декомпресснуть один раз и положить в параметры класса There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Пофиксил в следующем PR |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// | ||
// FilecoinTransactionBuilderTests.swift | ||
// BlockchainSdkTests | ||
// | ||
// Created by Aleksei Muraveinik on 29.08.24. | ||
// Copyright © 2024 Tangem AG. All rights reserved. | ||
// | ||
|
||
import XCTest | ||
@testable import BlockchainSdk | ||
|
||
final class FilecoinTransactionBuilderTests: XCTestCase { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. не увидел теста на размер транзакции, хоть и секп все равно его надо делать There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Пофиксил в следующем PR |
||
private let transactionBuilder = FilecoinTransactionBuilder( | ||
wallet: Wallet( | ||
blockchain: .filecoin, | ||
addresses: [ | ||
.default: PlainAddress( | ||
value: Constants.sourceAddress, | ||
publicKey: Wallet.PublicKey( | ||
seedKey: Constants.publicKey, | ||
derivationType: nil | ||
), | ||
type: .default | ||
) | ||
] | ||
) | ||
) | ||
|
||
private var transaction: Transaction { | ||
Transaction( | ||
amount: Amount( | ||
with: .filecoin, | ||
type: .coin, | ||
value: 0.01 | ||
), | ||
fee: Fee( | ||
Amount( | ||
with: .filecoin, | ||
type: .coin, | ||
value: (101225 * 1526328) / Blockchain.filecoin.decimalValue | ||
), | ||
parameters: FilecoinFeeParameters( | ||
gasUnitPrice: 101225, | ||
gasLimit: 1526328, | ||
gasPremium: 50612 | ||
) | ||
), | ||
sourceAddress: Constants.sourceAddress, | ||
destinationAddress: Constants.destinationAddress, | ||
changeAddress: Constants.sourceAddress | ||
) | ||
} | ||
|
||
func testBuildForSign() throws { | ||
let expected = Data(hex: "BEB93CCF5C85273B327AC5DCDD58CBF3066F57FC84B87CD20DC67DF69EC2D0A9") | ||
let actual = try transactionBuilder.buildForSign(transaction: transaction, nonce: 2) | ||
|
||
XCTAssertEqual(expected, actual) | ||
} | ||
|
||
func testBuildForSend() throws { | ||
let nonce: UInt64 = 2 | ||
let expected = FilecoinSignedTransactionBody( | ||
transactionBody: FilecoinTransactionBody( | ||
sourceAddress: Constants.sourceAddress, | ||
destinationAddress: Constants.destinationAddress, | ||
amount: "10000000000000000", | ||
nonce: nonce, | ||
gasUnitPrice: "101225", | ||
gasLimit: 1526328, | ||
gasPremium: "50612" | ||
), | ||
signature: FilecoinSignedTransactionBody.Signature( | ||
type: 1, | ||
signature: "Bogel9o9zvXUT+sC+nVpciGyHfBxWG6V4+xOawP6YrAU1OIbifvEHpRT/Elakv2X6mfUkbQzparvc2HyJBbXRwE=" | ||
) | ||
) | ||
|
||
let hashToSign = try transactionBuilder.buildForSign(transaction: transaction, nonce: nonce) | ||
|
||
let actual = try transactionBuilder.buildForSend( | ||
transaction: transaction, | ||
nonce: nonce, | ||
signatureInfo: SignatureInfo( | ||
signature: Constants.signature, | ||
publicKey: Constants.publicKey, | ||
hash: hashToSign | ||
) | ||
) | ||
|
||
XCTAssertEqual(expected, actual) | ||
} | ||
} | ||
|
||
private extension FilecoinTransactionBuilderTests { | ||
enum Constants { | ||
static let publicKey = Data(hex: "0374D0F81F42DDFE34114D533E95E6AE5FE6EA271C96F1FA505199FDC365AE9720") | ||
static let signature = Data(hex: "06881E97DA3DCEF5D44FEB02FA75697221B21DF071586E95E3EC4E6B03FA62B014D4E21B89FBC41E9453FC495A92FD97EA67D491B433A5AAEF7361F22416D74701") | ||
|
||
static let sourceAddress = "f1flbddhx4vwox3y3ux5bwgsgq2frzeiuvvdrjo7i" | ||
static let destinationAddress = "f1rluskhwvv5b3z36skltu4noszbc5stfihevbf2i" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
По поводу типов данных - я провалидирую корректность в следующем PRе (про WalletManager)