diff --git a/cmd/starknet/cmd/generate_raw_tx.go b/cmd/starknet/cmd/generate_raw_tx.go
index 67a8277c78dc9664cf0377c1b5b8090b9d236e06..73518f755e0b5d45d3a1ba975dc524a6de10433d 100644
--- a/cmd/starknet/cmd/generate_raw_tx.go
+++ b/cmd/starknet/cmd/generate_raw_tx.go
@@ -12,7 +12,9 @@ import (
 
 type Flags struct {
 	Contract   string
+	Salt       string
 	PrivateKey string
+	Datadir    string
 	Output     string
 }
 
@@ -27,17 +29,22 @@ func init() {
 	generateRawTxCmd.Flags().StringVarP(&flags.Contract, "contract", "c", "", "Path to compiled cairo contract in JSON format")
 	generateRawTxCmd.MarkFlagRequired("contract")
 
+	generateRawTxCmd.Flags().StringVarP(&flags.Salt, "salt", "s", "", "Cairo contract address salt")
+	generateRawTxCmd.MarkFlagRequired("salt")
+
 	generateRawTxCmd.Flags().StringVarP(&flags.PrivateKey, "private_key", "k", "", "Private key")
 	generateRawTxCmd.MarkFlagRequired("private_key")
 
-	generateRawTxCmd.Flags().StringVarP(&flags.Output, "output", "o", "", "Path to file where sign transaction will be saved")
+	rootCmd.PersistentFlags().StringVar(&flags.Datadir, "datadir", "", "path to Erigon working directory")
+
+	generateRawTxCmd.Flags().StringVarP(&flags.Output, "output", "o", "", "Path to file where sign transaction will be saved. Print to stdout if empty.")
 
 	generateRawTxCmd.RunE = func(cmd *cobra.Command, args []string) error {
 		rawTxGenerator := services.NewRawTxGenerator(flags.PrivateKey)
 
 		fs := os.DirFS("/")
 		buf := bytes.NewBuffer(nil)
-		err := rawTxGenerator.CreateFromFS(fs, strings.Trim(flags.Contract, "/"), buf)
+		err := rawTxGenerator.CreateFromFS(fs, strings.Trim(flags.Contract, "/"), []byte(flags.Salt), buf)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/starknet/services/raw_tx_generator.go b/cmd/starknet/services/raw_tx_generator.go
index 26df5b54f7ccbaa441835eddcedb1b525b5445af..c2006da4aefa177e29f12d7b610d505476b05cbb 100644
--- a/cmd/starknet/services/raw_tx_generator.go
+++ b/cmd/starknet/services/raw_tx_generator.go
@@ -27,7 +27,7 @@ type RawTxGenerator struct {
 	privateKey string
 }
 
-func (g RawTxGenerator) CreateFromFS(fileSystem fs.FS, contractFileName string, writer io.Writer) error {
+func (g RawTxGenerator) CreateFromFS(fileSystem fs.FS, contractFileName string, salt []byte, writer io.Writer) error {
 	privateKey, err := crypto.HexToECDSA(g.privateKey)
 	if err != nil {
 		return ErrInvalidPrivateKey
@@ -47,6 +47,7 @@ func (g RawTxGenerator) CreateFromFS(fileSystem fs.FS, contractFileName string,
 			Value: uint256.NewInt(1),
 			Gas:   1,
 			Data:  enc,
+			Salt:  salt,
 		},
 	}
 
diff --git a/cmd/starknet/services/raw_tx_generator_test.go b/cmd/starknet/services/raw_tx_generator_test.go
index bd912a3462133add995416cfd03ea0470f60ecf1..795af2be9a6dd2b3dbff9c98e1a4a1da402841fa 100644
--- a/cmd/starknet/services/raw_tx_generator_test.go
+++ b/cmd/starknet/services/raw_tx_generator_test.go
@@ -15,9 +15,10 @@ func TestCreate(t *testing.T) {
 		name       string
 		privateKey string
 		fileName   string
+		salt       string
 		want       string
 	}{
-		{name: "success", privateKey: privateKey, fileName: "contract_test.json", want: "03f86583127ed80180800180019637623232363136323639323233613230356235643764c080a0ceb955e6039bf37dbf77e4452a10b4a47906bbbd2f6dcf0c15bccb052d3bbb60a03de24d584a0a20523f55a137ebc651e2b092fbc3728d67c9fda09da9f0edd154"},
+		{name: "success", privateKey: privateKey, fileName: "contract_test.json", salt: "contract_address_salt", want: "03f87b83127ed8018080018001963762323236313632363932323361323035623564376495636f6e74726163745f616464726573735f73616c74c080a0ceb955e6039bf37dbf77e4452a10b4a47906bbbd2f6dcf0c15bccb052d3bbb60a03de24d584a0a20523f55a137ebc651e2b092fbc3728d67c9fda09da9f0edd154"},
 	}
 
 	fs := fstest.MapFS{
@@ -31,12 +32,13 @@ func TestCreate(t *testing.T) {
 			}
 
 			buf := bytes.NewBuffer(nil)
-			err := rawTxGenerator.CreateFromFS(fs, tt.fileName, buf)
-
+			err := rawTxGenerator.CreateFromFS(fs, tt.fileName, []byte(tt.salt), buf)
 			assertNoError(t, err)
 
-			if hex.EncodeToString(buf.Bytes()) != tt.want {
-				t.Error("got not equals want")
+			got := hex.EncodeToString(buf.Bytes())
+
+			if got != tt.want {
+				t.Errorf("got %q not equals want %q", got, tt.want)
 			}
 		})
 	}
@@ -62,7 +64,7 @@ func TestErrorCreate(t *testing.T) {
 			}
 
 			buf := bytes.NewBuffer(nil)
-			err := rawTxGenerator.CreateFromFS(fs, tt.fileName, buf)
+			err := rawTxGenerator.CreateFromFS(fs, tt.fileName, []byte{}, buf)
 
 			if tt.error != nil {
 				assertError(t, err, tt.error)
diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go
index 1cb0374658301427076e49b116f3319d638c0241..436daa400a57138bb18f6c234a6acf31fabc32a7 100644
--- a/core/types/legacy_tx.go
+++ b/core/types/legacy_tx.go
@@ -38,6 +38,7 @@ type CommonTx struct {
 	To      *common.Address `rlp:"nil"` // nil means contract creation
 	Value   *uint256.Int    // wei amount
 	Data    []byte          // contract invocation input data
+	Salt    []byte          // cairo contract address salt
 	V, R, S uint256.Int     // signature values
 }
 
@@ -65,6 +66,10 @@ func (ct CommonTx) GetData() []byte {
 	return ct.Data
 }
 
+func (ct CommonTx) GetSalt() []byte {
+	return ct.Salt
+}
+
 func (ct CommonTx) GetSender() (common.Address, bool) {
 	if sc := ct.from.Load(); sc != nil {
 		return sc.(common.Address), true
diff --git a/core/types/starknet_tx.go b/core/types/starknet_tx.go
index 4c4c504223904b63225f04afc33d1e5b34a3754a..c4c42423760f1ea9df74972b25f421f1f70611c1 100644
--- a/core/types/starknet_tx.go
+++ b/core/types/starknet_tx.go
@@ -33,29 +33,20 @@ func (tx *StarknetTransaction) DecodeRLP(s *rlp.Stream) error {
 		return err
 	}
 	var b []byte
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for ChainID: %d", len(b))
-	}
-	//tx.ChainID = new(uint256.Int).SetBytes(b)
+	tx.ChainID = new(uint256.Int).SetBytes(b)
 	if tx.Nonce, err = s.Uint(); err != nil {
 		return err
 	}
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for MaxPriorityFeePerGas: %d", len(b))
-	}
 	tx.Tip = new(uint256.Int).SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for MaxFeePerGas: %d", len(b))
-	}
 	tx.FeeCap = new(uint256.Int).SetBytes(b)
 	if tx.Gas, err = s.Uint(); err != nil {
 		return err
@@ -70,42 +61,33 @@ func (tx *StarknetTransaction) DecodeRLP(s *rlp.Stream) error {
 		tx.To = &common.Address{}
 		copy((*tx.To)[:], b)
 	}
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for Value: %d", len(b))
-	}
 	tx.Value = new(uint256.Int).SetBytes(b)
 	if tx.Data, err = s.Bytes(); err != nil {
 		return err
 	}
+	if tx.Salt, err = s.Bytes(); err != nil {
+		return err
+	}
 	// decode AccessList
 	tx.AccessList = AccessList{}
 	if err = decodeAccessList(&tx.AccessList, s); err != nil {
 		return err
 	}
 	// decode V
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for V: %d", len(b))
-	}
 	tx.V.SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for R: %d", len(b))
-	}
 	tx.R.SetBytes(b)
-	if b, err = s.Bytes(); err != nil {
+	if b, err = s.Uint256Bytes(); err != nil {
 		return err
 	}
-	if len(b) > 32 {
-		return fmt.Errorf("wrong size for S: %d", len(b))
-	}
 	tx.S.SetBytes(b)
 	return s.ListEnd()
 }
@@ -115,7 +97,7 @@ func (tx StarknetTransaction) GetPrice() *uint256.Int {
 }
 
 func (tx StarknetTransaction) GetTip() *uint256.Int {
-	panic("implement me")
+	return tx.Tip
 }
 
 func (tx StarknetTransaction) GetEffectiveGasTip(baseFee *uint256.Int) *uint256.Int {
@@ -123,7 +105,7 @@ func (tx StarknetTransaction) GetEffectiveGasTip(baseFee *uint256.Int) *uint256.
 }
 
 func (tx StarknetTransaction) GetFeeCap() *uint256.Int {
-	panic("implement me")
+	return tx.FeeCap
 }
 
 func (tx StarknetTransaction) Cost() *uint256.Int {
@@ -184,7 +166,7 @@ func (tx StarknetTransaction) GetAccessList() AccessList {
 }
 
 func (tx StarknetTransaction) RawSignatureValues() (*uint256.Int, *uint256.Int, *uint256.Int) {
-	panic("implement me")
+	return &tx.V, &tx.R, &tx.S
 }
 
 func (tx StarknetTransaction) MarshalBinary(w io.Writer) error {
@@ -269,6 +251,10 @@ func (tx StarknetTransaction) encodePayload(w io.Writer, b []byte, payloadSize,
 	if err := EncodeString(tx.Data, w, b); err != nil {
 		return err
 	}
+	// encode cairo contract address salt
+	if err := EncodeString(tx.Salt, w, b); err != nil {
+		return err
+	}
 	// prefix
 	if err := EncodeStructSizePrefix(accessListLen, w, b); err != nil {
 		return err
@@ -338,6 +324,7 @@ func (tx StarknetTransaction) payloadSize() (payloadSize int, nonceLen, gasLen,
 		valueLen = (tx.Value.BitLen() + 7) / 8
 	}
 	payloadSize += valueLen
+
 	// size of Data
 	payloadSize++
 	switch len(tx.Data) {
@@ -352,6 +339,22 @@ func (tx StarknetTransaction) payloadSize() (payloadSize int, nonceLen, gasLen,
 		}
 		payloadSize += len(tx.Data)
 	}
+
+	// size of cairo contract address salt
+	payloadSize++
+	switch len(tx.Salt) {
+	case 0:
+	case 1:
+		if tx.Salt[0] >= 128 {
+			payloadSize++
+		}
+	default:
+		if len(tx.Salt) >= 56 {
+			payloadSize += (bits.Len(uint(len(tx.Salt))) + 7) / 8
+		}
+		payloadSize += len(tx.Salt)
+	}
+
 	// size of AccessList
 	payloadSize++
 	accessListLen = accessListSize(tx.AccessList)
@@ -393,6 +396,7 @@ func (tx StarknetTransaction) copy() *StarknetTransaction {
 			Nonce:   tx.Nonce,
 			To:      tx.To,
 			Data:    common.CopyBytes(tx.Data),
+			Salt:    common.CopyBytes(tx.Salt),
 			Gas:     tx.Gas,
 			Value:   new(uint256.Int),
 		},
diff --git a/core/types/starknet_tx_test.go b/core/types/starknet_tx_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..44efdf6b2fe129a69048e7924057622c853dd8f3
--- /dev/null
+++ b/core/types/starknet_tx_test.go
@@ -0,0 +1,124 @@
+package types
+
+import (
+	"bytes"
+	"encoding/hex"
+	"github.com/holiman/uint256"
+	"github.com/ledgerwatch/erigon/common"
+	"github.com/ledgerwatch/erigon/crypto"
+	"github.com/ledgerwatch/erigon/params"
+	"github.com/ledgerwatch/erigon/rlp"
+	"github.com/stretchr/testify/require"
+	"golang.org/x/crypto/sha3"
+	"math/big"
+	"testing"
+)
+
+var (
+	chainConfig = params.AllEthashProtocolChanges
+	address     = common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b")
+)
+
+func TestStarknetTxDecodeRLP(t *testing.T) {
+	require := require.New(t)
+
+	privateKey, _ := crypto.HexToECDSA(generatePrivateKey(t))
+
+	signature, _ := crypto.Sign(sha3.New256().Sum(nil), privateKey)
+	signer := MakeSigner(chainConfig, 1)
+
+	cases := []struct {
+		name string
+		tx   *StarknetTransaction
+	}{
+		{name: "with data, without salt", tx: &StarknetTransaction{
+			CommonTx: CommonTx{
+				ChainID: uint256.NewInt(chainConfig.ChainID.Uint64()),
+				Nonce:   1,
+				Value:   uint256.NewInt(20),
+				Gas:     1,
+				To:      &address,
+				Data:    []byte("{\"abi\": []}"),
+				Salt:    []byte("contract_salt"),
+			},
+			Tip:    uint256.NewInt(1),
+			FeeCap: uint256.NewInt(1),
+		}},
+		{name: "with data and salt", tx: &StarknetTransaction{
+			CommonTx: CommonTx{
+				ChainID: uint256.NewInt(chainConfig.ChainID.Uint64()),
+				Nonce:   1,
+				Value:   uint256.NewInt(20),
+				Gas:     1,
+				To:      &address,
+				Data:    []byte("{\"abi\": []}"),
+				Salt:    []byte{},
+			},
+			Tip:    uint256.NewInt(1),
+			FeeCap: uint256.NewInt(1),
+		}},
+	}
+
+	for _, tt := range cases {
+		t.Run(tt.name, func(t *testing.T) {
+			tx := tt.tx
+
+			signedTx, err := tx.WithSignature(*signer, signature)
+			require.NoError(err)
+
+			buf := bytes.NewBuffer(nil)
+
+			err = signedTx.MarshalBinary(buf)
+			require.NoError(err)
+
+			encodedTx := buf.Bytes()
+
+			txn, err := DecodeTransaction(rlp.NewStream(bytes.NewReader(encodedTx), uint64(len(encodedTx))))
+			require.NoError(err)
+
+			require.Equal(signedTx.GetChainID(), txn.GetChainID())
+			require.Equal(signedTx.GetNonce(), txn.GetNonce())
+			require.Equal(signedTx.GetTip(), txn.GetTip())
+			require.Equal(signedTx.GetFeeCap(), txn.GetFeeCap())
+			require.Equal(signedTx.GetGas(), txn.GetGas())
+			require.Equal(signedTx.GetTo(), txn.GetTo())
+			require.Equal(signedTx.GetValue(), txn.GetValue())
+			require.Equal(signedTx.GetData(), txn.GetData())
+			require.Equal(signedTx.GetSalt(), txn.GetSalt())
+
+			txV, txR, txS := signedTx.RawSignatureValues()
+			txnV, txnR, txnS := txn.RawSignatureValues()
+
+			require.Equal(txV, txnV)
+			require.Equal(txR, txnR)
+			require.Equal(txS, txnS)
+		})
+	}
+}
+
+func generatePrivateKey(t testing.TB) string {
+	t.Helper()
+
+	privateKey, err := crypto.GenerateKey()
+	if err != nil {
+		t.Error(err)
+	}
+
+	return hex.EncodeToString(crypto.FromECDSA(privateKey))
+}
+
+func starknetTransaction(chainId *big.Int, address common.Address) *StarknetTransaction {
+	return &StarknetTransaction{
+		CommonTx: CommonTx{
+			ChainID: uint256.NewInt(chainId.Uint64()),
+			Nonce:   1,
+			Value:   uint256.NewInt(20),
+			Gas:     1,
+			To:      &address,
+			Data:    []byte("{\"abi\": []}"),
+			Salt:    []byte("contract_salt"),
+		},
+		Tip:    uint256.NewInt(1),
+		FeeCap: uint256.NewInt(1),
+	}
+}
diff --git a/core/types/transaction.go b/core/types/transaction.go
index d82935e50aae427ae692289648a2b6e34e933b3b..5e6cf722050164af4563ea70efc43c07bd9c0a90 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -68,6 +68,7 @@ type Transaction interface {
 	SigningHash(chainID *big.Int) common.Hash
 	Size() common.StorageSize
 	GetData() []byte
+	GetSalt() []byte
 	GetAccessList() AccessList
 	Protected() bool
 	RawSignatureValues() (*uint256.Int, *uint256.Int, *uint256.Int)