Skip to content

Commit

Permalink
Support RPC 0.7.0 (#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
DelevoXDG authored Mar 27, 2024
1 parent a8e2794 commit 6da127e
Show file tree
Hide file tree
Showing 21 changed files with 371 additions and 319 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
test_and_lint:
runs-on: macos-12
env:
DEVNET_SHA: 55191ee549b33ccbb0bc9d20dd929e39832a5ea5
DEVNET_SHA: fa1238e8039a53101b5d2d764d3622ff0403a527
steps:
- uses: actions/checkout@v3

Expand Down
22 changes: 22 additions & 0 deletions Sources/Starknet/Accounts/StarknetAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,28 @@ public class StarknetAccount: StarknetAccountProtocol {
return try await provider.addInvokeTransaction(signedTransaction)
}

public func executeV1(calls: [StarknetCall], estimateFeeMultiplier: Double) async throws -> StarknetInvokeTransactionResponse {
let nonce = try await getNonce()
let feeEstimate = try await estimateFeeV1(calls: calls, nonce: nonce)
let maxFee = feeEstimate.toMaxFee(multiplier: estimateFeeMultiplier)

let params = StarknetInvokeParamsV1(nonce: nonce, maxFee: maxFee)
let signedTransaction = try signV1(calls: calls, params: params, forFeeEstimation: false)

return try await provider.addInvokeTransaction(signedTransaction)
}

public func executeV3(calls: [StarknetCall], estimateAmountMultiplier: Double, estimateUnitPriceMultiplier: Double) async throws -> StarknetInvokeTransactionResponse {
let nonce = try await getNonce()
let feeEstimate = try await estimateFeeV3(calls: calls, nonce: nonce)
let resourceBounds = feeEstimate.toResourceBounds(amountMultiplier: estimateAmountMultiplier, unitPriceMultiplier: estimateUnitPriceMultiplier)

let params = StarknetInvokeParamsV3(nonce: nonce, l1ResourceBounds: resourceBounds.l1Gas)
let signedTransaction = try signV3(calls: calls, params: params, forFeeEstimation: false)

return try await provider.addInvokeTransaction(signedTransaction)
}

public func estimateFeeV1(calls: [StarknetCall], nonce: Felt, skipValidate: Bool) async throws -> StarknetFeeEstimate {
let params = StarknetInvokeParamsV1(nonce: nonce, maxFee: .zero)
let signedTransaction = try signV1(calls: calls, params: params, forFeeEstimation: true)
Expand Down
50 changes: 46 additions & 4 deletions Sources/Starknet/Accounts/StarknetAccountProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,34 @@ public protocol StarknetAccountProtocol {
/// - Returns: InvokeTransactionResponse, containing transaction hash of submitted transaction.
func executeV3(calls: [StarknetCall], params: StarknetOptionalInvokeParamsV3) async throws -> StarknetInvokeTransactionResponse

/// Execute list of calls as invoke transaction v1
/// Execute list of calls as invoke transaction v1 with automatically estimated fee that will be multiplied by the specified multiplier when max fee is calculated.
///
/// - Parameters:
/// - calls: list of calls to be executed.
/// - estimateFeeMultiplier: multiplier for the estimated fee.
///
/// - Returns: InvokeTransactionResponse, containing transaction hash of submitted transaction.
func executeV1(calls: [StarknetCall], estimateFeeMultiplier: Double) async throws -> StarknetInvokeTransactionResponse

/// Execute list of calls as invoke transaction v3 with automatically estimated fee that will be multiplied by the specified multipliers when resource bounds are calculated.
///
/// - Parameters:
/// - calls: list of calls to be executed.
/// - estimateAmountMultiplier: multiplier for the estimated amount.
/// - estimateUnitPriceMultiplier: multiplier for the estimated unit price.
///
/// - Returns: InvokeTransactionResponse, containing transaction hash of submitted transaction.
func executeV3(calls: [StarknetCall], estimateAmountMultiplier: Double, estimateUnitPriceMultiplier: Double) async throws -> StarknetInvokeTransactionResponse

/// Execute list of calls as invoke transaction v1 with automatically estimated fee
///
/// - Parameters:
/// - calls: list of calls to be executed.
///
/// - Returns: InvokeTransactionResponse, containing transaction hash of submitted transaction.
func executeV1(calls: [StarknetCall]) async throws -> StarknetInvokeTransactionResponse

/// Execute list of calls as invoke transaction v3
/// Execute list of calls as invoke transaction v3 with automatically estimated fee
///
/// - Parameters:
/// - calls: list of calls to be executed.
Expand Down Expand Up @@ -269,7 +288,30 @@ public extension StarknetAccountProtocol {
try await executeV3(calls: [call], params: params)
}

/// Execute a call as invoke transaction v1
/// Execute a call as invoke transaction v1 with automatically estimated fee that will be multiplied by the specified multiplier when max fee is calculated.
///
/// - Parameters:
/// - call: a call to be executed.
/// - estimateFeeMultiplier: multiplier for the estimated fee.
///
/// - Returns: InvokeTransactionResponse, containing transaction hash of submitted transaction.
func executeV1(call: StarknetCall, estimateFeeMultiplier: Double) async throws -> StarknetInvokeTransactionResponse {
try await executeV1(calls: [call], estimateFeeMultiplier: estimateFeeMultiplier)
}

/// Execute a call as invoke transaction v3 with automatically estimated fee that will be multiplied by the specified multipliers when resource bounds are calculated.
///
/// - Parameters:
/// - call: a call to be executed.
/// - estimateAmountMultiplier: multiplier for the estimated amount.
/// - estimateUnitPriceMultiplier: multiplier for the estimated unit price.
///
/// - Returns: InvokeTransactionResponse, containing transaction hash of submitted transaction.
func executeV3(call: StarknetCall, estimateAmountMultiplier: Double, estimateUnitPriceMultiplier: Double) async throws -> StarknetInvokeTransactionResponse {
try await executeV3(calls: [call], estimateAmountMultiplier: estimateAmountMultiplier, estimateUnitPriceMultiplier: estimateUnitPriceMultiplier)
}

/// Execute a call as invoke transaction v1 with automatically estimated fee
///
/// - Parameters:
/// - call: a call to be executed.
Expand All @@ -279,7 +321,7 @@ public extension StarknetAccountProtocol {
try await executeV1(calls: [call])
}

/// Execute a call as invoke transaction v3
/// Execute a call as invoke transaction v3 with automatically estimated fee
///
/// - Parameters:
/// - call: a call to be executed.
Expand Down
41 changes: 22 additions & 19 deletions Sources/Starknet/Crypto/FeeCalculation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,43 @@ import BigInt
import Foundation

public extension StarknetFeeEstimate {
/// Convert estimated fee to resource bounds with added overhead
/// Convert estimated fee to resource bounds with applied multipliers
///
/// Add overhead to estimated fee. Calculates multiplier as m = round((1 + ovehead) \* 100%).
/// Then multiplies fee by m and does integer division by 100.
/// Calculates `maxAmount = overallFee / gasPrice`, unless `gasPrice` is 0, then `maxAmount` is 0.
/// Calculates `maxPricePerUnit = gasPrice`.
/// Then multiplies `maxAmount` by **round((amountMultiplier) \* 100)** and `maxPricePerUnit` by **round((unitPriceMultiplier) \* 100)** and performs integer division by 100 on both.
///
/// - Parameters:
/// - amountOverhead: how big overhead should be added (as a fraction of amount) to the amount, defaults to 0.1
/// - unitPriceOverhead: how big overhead should be added (as a fraction of unit price) to the unit price, defaults to 0.5
/// - amountMultiplier: multiplier for max amount, defaults to 1.5.
/// - unitPriceMultiplier: multiplier for max price per unit, defaults to 1.5.
///
/// - Returns: resource bounds with added overhead
func toResourceBounds(amountOverhead: Double = 0.1, unitPriceOverhead: Double = 0.5) -> StarknetResourceBoundsMapping {
let maxAmount = addOverhead(self.gasConsumed.value, amountOverhead).toUInt64AsHexClamped()
let maxUnitPrice = addOverhead(self.gasPrice.value, unitPriceOverhead).toUInt128AsHexClamped()
/// - Returns: resource bounds with applied multipliers
func toResourceBounds(amountMultiplier: Double = 1.5, unitPriceMultiplier: Double = 1.5) -> StarknetResourceBoundsMapping {
let maxAmount = self.gasPrice == .zero ? UInt64AsHex.zero : (self.overallFee.value / self.gasPrice.value).applyMultiplier(amountMultiplier).toUInt64AsHexClamped()

let maxUnitPrice = self.gasPrice.value.applyMultiplier(unitPriceMultiplier).toUInt128AsHexClamped()

let l1Gas = StarknetResourceBounds(maxAmount: maxAmount, maxPricePerUnit: maxUnitPrice)
return StarknetResourceBoundsMapping(l1Gas: l1Gas)
}

/// Add overhead to estimated fee
/// Convert estimated fee to max fee with applied multiplier.
///
/// Add overhead to estimated fee. Calculates multiplier as m = round((1 + ovehead) \* 100%).
/// Then multiplies fee by m and does integer division by 100.
/// Multiplies `overallFee` by **round(multiplier \* 100)** and performs integer division by 100.
///
/// - Parameters:
/// - overhead: how big overhead should be added (as a fraction of fee) to the fee, defaults to 0.1
/// - multiplier: multiplier for estimated fee, defaults to 1.5.
///
/// - Returns: fee with added overhead
func toMaxFee(overhead: Double = 0.5) -> Felt {
addOverhead(self.overallFee.value, overhead).toFeltClamped()
/// - Returns: fee with applied multiplier
func toMaxFee(multiplier: Double = 1.5) -> Felt {
self.overallFee.value.applyMultiplier(multiplier).toFeltClamped()
}
}

private func addOverhead(_ value: BigUInt, _ overhead: Double) -> BigUInt {
let multiplier = BigUInt(Int((1.0 + overhead) * 100))
private extension BigUInt {
func applyMultiplier(_ multiplier: Double) -> BigUInt {
let multiplier = BigUInt(Int(multiplier * 100))

return value.multiplied(by: multiplier).quotientAndRemainder(dividingBy: 100).quotient
return self.multiplied(by: multiplier).quotientAndRemainder(dividingBy: 100).quotient
}
}
4 changes: 4 additions & 0 deletions Sources/Starknet/Data/Responses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ public struct StarknetInvokeTransactionResponse: Decodable, Equatable {
public struct StarknetFeeEstimate: Decodable, Equatable {
public let gasConsumed: Felt
public let gasPrice: Felt
public let dataGasConsumed: Felt
public let dataGasPrice: Felt
public let overallFee: Felt
public let feeUnit: StarknetPriceUnit

enum CodingKeys: String, CodingKey {
case gasConsumed = "gas_consumed"
case gasPrice = "gas_price"
case dataGasConsumed = "data_gas_consumed"
case dataGasPrice = "data_gas_price"
case overallFee = "overall_fee"
case feeUnit = "unit"
}
Expand Down
55 changes: 54 additions & 1 deletion Sources/Starknet/Data/Transaction/Data/ExecutionResources.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
import Foundation

public struct StarknetExecutionResources: Decodable, Equatable {
public protocol StarknetResources: Decodable, Equatable {
var steps: Int { get }
var memoryHoles: Int? { get }
var rangeCheckApplications: Int? { get }
var pedersenApplications: Int? { get }
var poseidonApplications: Int? { get }
var ecOpApplications: Int? { get }
var ecdsaApplications: Int? { get }
var bitwiseApplications: Int? { get }
var keccakApplications: Int? { get }
var segmentArena: Int? { get }
}

public struct StarknetComputationResources: StarknetResources {
public let steps: Int
public let memoryHoles: Int?
public let rangeCheckApplications: Int?
public let pedersenApplications: Int?
public let poseidonApplications: Int?
public let ecOpApplications: Int?
public let ecdsaApplications: Int?
public let bitwiseApplications: Int?
public let keccakApplications: Int?
public let segmentArena: Int?

enum CodingKeys: String, CodingKey {
case steps
case memoryHoles = "memory_holes"
case rangeCheckApplications = "range_check_builtin_applications"
case pedersenApplications = "pedersen_builtin_applications"
case poseidonApplications = "poseidon_builtin_applications"
case ecOpApplications = "ec_op_builtin_applications"
case ecdsaApplications = "ecdsa_builtin_applications"
case bitwiseApplications = "bitwise_builtin_applications"
case keccakApplications = "keccak_builtin_applications"
case segmentArena = "segment_arena_builtin"
}
}

public struct StarknetExecutionResources: StarknetResources {
public let steps: Int
public let memoryHoles: Int?
public let rangeCheckApplications: Int?
Expand All @@ -10,6 +49,8 @@ public struct StarknetExecutionResources: Decodable, Equatable {
public let ecdsaApplications: Int?
public let bitwiseApplications: Int?
public let keccakApplications: Int?
public let segmentArena: Int?
public let dataAvailability: StarknetDataAvailability

enum CodingKeys: String, CodingKey {
case steps
Expand All @@ -21,5 +62,17 @@ public struct StarknetExecutionResources: Decodable, Equatable {
case ecdsaApplications = "ecdsa_builtin_applications"
case bitwiseApplications = "bitwise_builtin_applications"
case keccakApplications = "keccak_builtin_applications"
case segmentArena = "segment_arena_builtin"
case dataAvailability = "data_availability"
}
}

public struct StarknetDataAvailability: Decodable, Equatable {
public let l1Gas: Int
public let l1DataGas: Int

enum CodingKeys: String, CodingKey {
case l1Gas = "l1_gas"
case l1DataGas = "l1_data_gas"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation

public enum StarknetTransactionVersion: String, Codable {
case v0 = "0x0"
case v1 = "0x1"
case v1Query = "0x100000000000000000000000000000001"
case v2 = "0x2"
case v2Query = "0x100000000000000000000000000000002"
case v3 = "0x3"
case v3Query = "0x100000000000000000000000000000003"

public var value: Felt {
Felt(fromHex: self.rawValue)!
}
}
Loading

0 comments on commit 6da127e

Please sign in to comment.