diff --git a/account/account.go b/account/account.go index 75c289c9..1402dd07 100644 --- a/account/account.go +++ b/account/account.go @@ -215,12 +215,20 @@ func (account *Account) TransactionHashDeployAccount(tx rpc.DeployAccountType, c if err != nil { return nil, err } + tipUint64, err := txn.Tip.ToUint64() + if err != nil { + return nil, err + } + tipAndResourceHash, err := tipAndResourcesHash(tipUint64, txn.ResourceBounds) + if err != nil { + return nil, err + } // https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/transactions/#deploy_account_hash_calculation return crypto.PoseidonArray( PREFIX_DEPLOY_ACCOUNT, txnVersionFelt, contractAddress, - tipAndResourcesHash(txn.Tip.Impl().Uint64(), txn.ResourceBounds), + tipAndResourceHash, crypto.PoseidonArray(txn.PayMasterData...), account.ChainId, txn.Nonce, @@ -313,12 +321,19 @@ func (account *Account) TransactionHashInvoke(tx rpc.InvokeTxnType) (*felt.Felt, if err != nil { return nil, err } - + tipUint64, err := txn.Tip.ToUint64() + if err != nil { + return nil, err + } + tipAndResourceHash, err := tipAndResourcesHash(tipUint64, txn.ResourceBounds) + if err != nil { + return nil, err + } return crypto.PoseidonArray( PREFIX_TRANSACTION, txnVersionFelt, txn.SenderAddress, - tipAndResourcesHash(txn.Tip.Impl().Uint64(), txn.ResourceBounds), + tipAndResourceHash, crypto.PoseidonArray(txn.PayMasterData...), account.ChainId, txn.Nonce, @@ -330,10 +345,18 @@ func (account *Account) TransactionHashInvoke(tx rpc.InvokeTxnType) (*felt.Felt, return nil, ErrTxnTypeUnSupported } -func tipAndResourcesHash(tip uint64, resourceBounds rpc.ResourceBoundsMapping) *felt.Felt { - l1Bounds := new(felt.Felt).SetBytes(resourceBounds.L1Gas.Bytes(rpc.ResourceL1Gas)) - l2Bounds := new(felt.Felt).SetBytes(resourceBounds.L2Gas.Bytes(rpc.ResourceL2Gas)) - return crypto.PoseidonArray(new(felt.Felt).SetUint64(tip), l1Bounds, l2Bounds) +func tipAndResourcesHash(tip uint64, resourceBounds rpc.ResourceBoundsMapping) (*felt.Felt, error) { + l1Bytes, err := resourceBounds.L1Gas.Bytes(rpc.ResourceL1Gas) + if err != nil { + return nil, err + } + l2Bytes, err := resourceBounds.L2Gas.Bytes(rpc.ResourceL2Gas) + if err != nil { + return nil, err + } + l1Bounds := new(felt.Felt).SetBytes(l1Bytes) + l2Bounds := new(felt.Felt).SetBytes(l2Bytes) + return crypto.PoseidonArray(new(felt.Felt).SetUint64(tip), l1Bounds, l2Bounds), nil } func dataAvailabilityMode(feeDAMode, nonceDAMode rpc.DataAvailabilityMode) (uint64, error) { @@ -432,12 +455,29 @@ func (account *Account) TransactionHashDeclare(tx rpc.DeclareTxnType) (*felt.Fel if err != nil { return nil, err } + tipUint64, err := txn.Tip.ToUint64() + if err != nil { + return nil, err + } + + _, err = txn.ResourceBounds.L1Gas.Bytes(rpc.ResourceL1Gas) + if err != nil { + return nil, err + } + _, err = txn.ResourceBounds.L2Gas.Bytes(rpc.ResourceL2Gas) + if err != nil { + return nil, err + } + tipAndResourceHash, err := tipAndResourcesHash(tipUint64, txn.ResourceBounds) + if err != nil { + return nil, err + } return crypto.PoseidonArray( PREFIX_DECLARE, txnVersionFelt, txn.SenderAddress, - tipAndResourcesHash(txn.Tip.Impl().Uint64(), txn.ResourceBounds), + tipAndResourceHash, crypto.PoseidonArray(txn.PayMasterData...), account.ChainId, txn.Nonce, diff --git a/account/account_test.go b/account/account_test.go index c9132209..18c4cacb 100644 --- a/account/account_test.go +++ b/account/account_test.go @@ -780,15 +780,15 @@ func TestTransactionHashDeclare(t *testing.T) { ClassHash: utils.TestHexToFelt(t, "0x5ae9d09292a50ed48c5930904c880dab56e85b825022a7d689cfc9e65e01ee7"), ResourceBounds: rpc.ResourceBoundsMapping{ L1Gas: rpc.ResourceBounds{ - MaxAmount: utils.TestHexToFelt(t, "0x186a0"), - MaxPricePerUnit: utils.TestHexToFelt(t, "0x2540be400"), + MaxAmount: "0x186a0", + MaxPricePerUnit: "0x2540be400", }, L2Gas: rpc.ResourceBounds{ - MaxAmount: utils.TestHexToFelt(t, "0x0"), - MaxPricePerUnit: utils.TestHexToFelt(t, "0x0"), + MaxAmount: "0x0", + MaxPricePerUnit: "0x0", }, }, - Tip: utils.TestHexToFelt(t, "0x0"), + Tip: "0x0", PayMasterData: []*felt.Felt{}, AccountDeploymentData: []*felt.Felt{}, NonceDataMode: rpc.DAModeL1, @@ -833,15 +833,15 @@ func TestTransactionHashInvokeV3(t *testing.T) { utils.TestHexToFelt(t, "0x6bef4745194c9447fdc8dd3aec4fc738ab0a560b0d2c7bf62fbf58aef3abfc5")}, ResourceBounds: rpc.ResourceBoundsMapping{ L1Gas: rpc.ResourceBounds{ - MaxAmount: utils.TestHexToFelt(t, "0x186a0"), - MaxPricePerUnit: utils.TestHexToFelt(t, "0x5af3107a4000"), + MaxAmount: "0x186a0", + MaxPricePerUnit: "0x5af3107a4000", }, L2Gas: rpc.ResourceBounds{ - MaxAmount: utils.TestHexToFelt(t, "0x0"), - MaxPricePerUnit: utils.TestHexToFelt(t, "0x0"), + MaxAmount: "0x0", + MaxPricePerUnit: "0x0", }, }, - Tip: utils.TestHexToFelt(t, "0x0"), + Tip: "0x0", PayMasterData: []*felt.Felt{}, AccountDeploymentData: []*felt.Felt{}, SenderAddress: utils.TestHexToFelt(t, "0x3f6f3bc663aedc5285d6013cc3ffcbc4341d86ab488b8b68d297f8258793c41"), @@ -905,15 +905,15 @@ func TestTransactionHashdeployAccount(t *testing.T) { utils.TestHexToFelt(t, "0x4daebba599f860daee8f6e100601d98873052e1c61530c630cc4375c6bd48e3")}, ResourceBounds: rpc.ResourceBoundsMapping{ L1Gas: rpc.ResourceBounds{ - MaxAmount: utils.TestHexToFelt(t, "0x186a0"), - MaxPricePerUnit: utils.TestHexToFelt(t, "0x5af3107a4000"), + MaxAmount: "0x186a0", + MaxPricePerUnit: "0x5af3107a4000", }, L2Gas: rpc.ResourceBounds{ - MaxAmount: utils.TestHexToFelt(t, "0x0"), - MaxPricePerUnit: utils.TestHexToFelt(t, "0x0"), + MaxAmount: "0x0", + MaxPricePerUnit: "0x0", }, }, - Tip: utils.TestHexToFelt(t, "0x0"), + Tip: "0x0", PayMasterData: []*felt.Felt{}, NonceDataMode: rpc.DAModeL1, FeeMode: rpc.DAModeL1, diff --git a/rpc/types_broadcast_transaction.go b/rpc/types_broadcast_transaction.go index 69264735..0232f136 100644 --- a/rpc/types_broadcast_transaction.go +++ b/rpc/types_broadcast_transaction.go @@ -66,7 +66,7 @@ type BroadcastDeclareTxnV3 struct { Nonce *felt.Felt `json:"nonce"` ContractClass *ContractClass `json:"contract_class"` ResourceBounds ResourceBoundsMapping `json:"resource_bounds"` - Tip *felt.Felt `json:"tip"` + Tip U64 `json:"tip"` // The data needed to allow the paymaster to pay for the transaction in native tokens PayMasterData []*felt.Felt `json:"paymaster_data"` // The data needed to deploy the account contract from which this tx will be initiated diff --git a/rpc/types_contract.go b/rpc/types_contract.go index e5fd9c84..7dc88b25 100644 --- a/rpc/types_contract.go +++ b/rpc/types_contract.go @@ -6,12 +6,33 @@ import ( "encoding/base64" "encoding/json" "fmt" + "strconv" + "strings" "github.com/NethermindEth/juno/core/felt" ) +// An integer number in hex format (0x...) type NumAsHex string +// 64 bit integers, represented by hex string of length at most 16 +type U64 string + +// ToUint64 converts the U64 type to a uint64. +func (u U64) ToUint64() (uint64, error) { + hexStr := strings.TrimPrefix(string(u), "0x") + + val, err := strconv.ParseUint(hexStr, 16, 64) + if err != nil { + return 0, fmt.Errorf("failed to parse hex string: %v", err) + } + + return val, nil +} + +// 64 bit integers, represented by hex string of length at most 32 +type U128 string + type DeprecatedCairoEntryPoint struct { // The offset of the entry point in the program Offset NumAsHex `json:"offset"` @@ -227,7 +248,9 @@ type FunctionABIEntry struct { // IsType returns the ABIType of the StructABIEntry. // // Parameters: -// none +// +// none +// // Returns: // - ABIType: the ABIType func (s *StructABIEntry) IsType() ABIType { @@ -237,7 +260,9 @@ func (s *StructABIEntry) IsType() ABIType { // IsType returns the ABIType of the EventABIEntry. // // Parameters: -// none +// +// none +// // Returns: // - ABIType: the ABIType func (e *EventABIEntry) IsType() ABIType { @@ -247,7 +272,9 @@ func (e *EventABIEntry) IsType() ABIType { // IsType returns the ABIType of the FunctionABIEntry. // // Parameters: -// none +// +// none +// // Returns: // - ABIType: the ABIType func (f *FunctionABIEntry) IsType() ABIType { diff --git a/rpc/types_transaction.go b/rpc/types_transaction.go index 623be52e..96e26660 100644 --- a/rpc/types_transaction.go +++ b/rpc/types_transaction.go @@ -55,7 +55,7 @@ type InvokeTxnV3 struct { Signature []*felt.Felt `json:"signature"` Nonce *felt.Felt `json:"nonce"` ResourceBounds ResourceBoundsMapping `json:"resource_bounds"` - Tip *felt.Felt `json:"tip"` + Tip U64 `json:"tip"` // The data needed to allow the paymaster to pay for the transaction in native tokens PayMasterData []*felt.Felt `json:"paymaster_data"` // The data needed to deploy the account contract from which this tx will be initiated @@ -118,7 +118,7 @@ type DeclareTxnV3 struct { Nonce *felt.Felt `json:"nonce"` ClassHash *felt.Felt `json:"class_hash"` ResourceBounds ResourceBoundsMapping `json:"resource_bounds"` - Tip *felt.Felt `json:"tip"` + Tip U64 `json:"tip"` // The data needed to allow the paymaster to pay for the transaction in native tokens PayMasterData []*felt.Felt `json:"paymaster_data"` // The data needed to deploy the account contract from which this tx will be initiated @@ -162,22 +162,30 @@ const ( type ResourceBounds struct { // The max amount of the resource that can be used in the tx - MaxAmount *felt.Felt `json:"max_amount"` + MaxAmount U64 `json:"max_amount"` // The max price per unit of this resource for this tx - MaxPricePerUnit *felt.Felt `json:"max_price_per_unit"` + MaxPricePerUnit U128 `json:"max_price_per_unit"` } -func (rb ResourceBounds) Bytes(resource Resource) []byte { +func (rb ResourceBounds) Bytes(resource Resource) ([]byte, error) { const eight = 8 maxAmountBytes := make([]byte, eight) - binary.BigEndian.PutUint64(maxAmountBytes, rb.MaxAmount.Impl().Uint64()) - maxPriceBytes := rb.MaxPricePerUnit.Bytes() + maxAmountUint64, err := rb.MaxAmount.ToUint64() + if err != nil { + return nil, err + } + binary.BigEndian.PutUint64(maxAmountBytes, maxAmountUint64) + maxPricePerUnitFelt, err := new(felt.Felt).SetString(string(rb.MaxPricePerUnit)) + if err != nil { + return nil, err + } + maxPriceBytes := maxPricePerUnitFelt.Bytes() return utils.Flatten( []byte{0}, []byte(resource), maxAmountBytes, maxPriceBytes[16:], // uint128. - ) + ), nil } // DeployTxn The structure of a deploy transaction. Note that this transaction type is deprecated and will no longer be supported in future versions @@ -217,7 +225,7 @@ type DeployAccountTxnV3 struct { ConstructorCalldata []*felt.Felt `json:"constructor_calldata"` ClassHash *felt.Felt `json:"class_hash"` ResourceBounds ResourceBoundsMapping `json:"resource_bounds"` - Tip *felt.Felt `json:"tip"` + Tip U64 `json:"tip"` // The data needed to allow the paymaster to pay for the transaction in native tokens PayMasterData []*felt.Felt `json:"paymaster_data"` // The storage domain of the account's nonce (an account has a nonce per DA mode)