Skip to content

Commit 44729bd

Browse files
committed
feat: added implementation of MsgExecutePayload
1 parent e7410c5 commit 44729bd

File tree

15 files changed

+3761
-135
lines changed

15 files changed

+3761
-135
lines changed

api/crosschain/v1/params.pulsar.go

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

api/crosschain/v1/tx.pulsar.go

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

api/crosschain/v1/tx_grpc.pb.go

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

proto/crosschain/v1/params.proto

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,20 @@ message AdminParams {
2929

3030
// The verifier precompile contract address (EVM).
3131
string verifier_precompile = 2;
32+
}
33+
34+
// CrossChainPayload mirrors the Solidity struct
35+
message CrossChainPayload {
36+
option (amino.name) = "crosschain/crosschain_payload";
37+
option (gogoproto.equal) = true;
38+
option (gogoproto.goproto_stringer) = false;
39+
40+
string target = 1; // EVM address as hex string (0x...)
41+
string value = 2; // Amount in wei as string (uint256)
42+
bytes data = 3; // ABI-encoded calldata
43+
string gas_limit = 4; // uint256 as string
44+
string max_fee_per_gas = 5; // uint256 as string
45+
string max_priority_fee_per_gas = 6; // uint256 as string
46+
string nonce = 7; // uint256 as string
47+
string deadline = 8; // uint256 as string
3248
}

proto/crosschain/v1/tx.proto

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ service Msg {
2626

2727
// MintPush defines a message to mint PUSH tokens to a smart account,
2828
rpc MintPush(MsgMintPush) returns (MsgMintPushResponse);
29+
30+
// ExecutePayload defines a message for executing a cross-chain payload
31+
rpc ExecutePayload(MsgExecutePayload) returns (MsgExecutePayloadResponse);
2932
}
3033

3134
// MsgUpdateParams is the Msg/UpdateParams request type.
@@ -108,4 +111,25 @@ message MsgMintPush {
108111
}
109112

110113
// MsgMintPushResponse defines the response for MsgMintPush.
111-
message MsgMintPushResponse {}
114+
message MsgMintPushResponse {}
115+
116+
// MsgExecutePayload defines a message for executing a cross-chain payload
117+
message MsgExecutePayload {
118+
option (amino.name) = "crosschain/MsgExecutePayload";
119+
option (cosmos.msg.v1.signer) = "signer";
120+
121+
// signer is the Cosmos address initiating the tx (used for tx signing)
122+
string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
123+
124+
// caip_string is used for generating deterministic salt for the smart account
125+
string caip_string = 2;
126+
127+
// payload is the crosschain payload to be executed
128+
CrossChainPayload crosschain_payload = 3;
129+
130+
// signature is the signature of the payload by user
131+
bytes signature = 4;
132+
}
133+
134+
// MsgExecutePayloadResponse defines the response for MsgExecutePayload.
135+
message MsgExecutePayloadResponse {}

x/crosschain/autocli.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
4242
RpcMethod: "MintPush",
4343
Use: "mint-push [tx-hash] [caip-string]",
4444
},
45+
{
46+
RpcMethod: "ExecutePayload",
47+
Use: "execute-payload [caip-string] [target] [value] [data-hex] [gas-limit] [max-fee-per-gas] [max-priority-fee-per-gas] [nonce] [deadline] [signature-hex]",
48+
},
4549
},
4650
},
4751
}

x/crosschain/client/cli/tx.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package cli
22

33
import (
4+
"encoding/hex"
45
"strconv"
6+
"strings"
57

68
"github.com/spf13/cobra"
79

@@ -192,3 +194,64 @@ func MsgMintPush() *cobra.Command {
192194
flags.AddTxFlagsToCmd(cmd)
193195
return cmd
194196
}
197+
198+
func MsgExecutePayload() *cobra.Command {
199+
cmd := &cobra.Command{
200+
Use: "execute-payload [caip-string] [target] [value] [data-hex] [gas-limit] [max-fee-per-gas] [max-priority-fee-per-gas] [nonce] [deadline] [signature-hex]",
201+
Short: "Execute a cross-chain payload with a signature",
202+
Args: cobra.ExactArgs(9),
203+
RunE: func(cmd *cobra.Command, args []string) error {
204+
cliCtx, err := client.GetClientTxContext(cmd)
205+
if err != nil {
206+
return err
207+
}
208+
209+
senderAddress := cliCtx.GetFromAddress()
210+
211+
caipString := args[0]
212+
target := args[1]
213+
value := args[2]
214+
215+
data, err := hex.DecodeString(strings.TrimPrefix(args[3], "0x"))
216+
if err != nil {
217+
return err
218+
}
219+
220+
gasLimit := args[4]
221+
maxFeePerGas := args[5]
222+
maxPriorityFeePerGas := args[6]
223+
nonce := args[7]
224+
deadline := args[8]
225+
226+
signature, err := hex.DecodeString(strings.TrimPrefix(args[9], "0x"))
227+
if err != nil {
228+
return err
229+
}
230+
231+
msg := &types.MsgExecutePayload{
232+
Signer: senderAddress.String(),
233+
CaipString: caipString,
234+
CrosschainPayload: &types.CrossChainPayload{
235+
Target: target,
236+
Value: value,
237+
Data: data,
238+
GasLimit: gasLimit,
239+
MaxFeePerGas: maxFeePerGas,
240+
MaxPriorityFeePerGas: maxPriorityFeePerGas,
241+
Nonce: nonce,
242+
Deadline: deadline,
243+
},
244+
Signature: signature,
245+
}
246+
247+
if err := msg.Validate(); err != nil {
248+
return err
249+
}
250+
251+
return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg)
252+
},
253+
}
254+
255+
flags.AddTxFlagsToCmd(cmd)
256+
return cmd
257+
}

x/crosschain/keeper/keeper_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ func SetupTest(t *testing.T) *testFixture {
8787
registerBaseSDKModules(logger, f, encCfg, keys, accountAddressCodec, validatorAddressCodec, consensusAddressCodec)
8888

8989
// Setup Keeper.
90-
f.k = keeper.NewKeeper(encCfg.Codec, runtime.NewKVStoreService(keys[types.ModuleName]), logger, f.govModAddr, &evmkeeper.Keeper{})
90+
f.k = keeper.NewKeeper(encCfg.Codec, runtime.NewKVStoreService(keys[types.ModuleName]), logger, f.govModAddr, &evmkeeper.Keeper{}, f.bankkeeper)
9191
f.msgServer = keeper.NewMsgServerImpl(f.k)
9292
f.queryServer = keeper.NewQuerier(f.k)
93-
f.appModule = module.NewAppModule(encCfg.Codec, f.k, &evmkeeper.Keeper{})
93+
f.appModule = module.NewAppModule(encCfg.Codec, f.k, &evmkeeper.Keeper{}, &f.bankkeeper)
9494

9595
return f
9696
}

x/crosschain/keeper/msg_server.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package keeper
33
import (
44
"context"
55
"encoding/hex"
6+
"math/big"
67
"strings"
78

89
"fmt"
@@ -28,9 +29,16 @@ var _ types.MsgServer = msgServer{}
2829

2930
func hexToBytes(hexStr string) ([]byte, error) {
3031
hexStr = strings.TrimPrefix(hexStr, "0x")
32+
fmt.Println("Hex string:", hexStr)
33+
fmt.Println(hex.DecodeString(hexStr))
3134
return hex.DecodeString(hexStr)
3235
}
3336

37+
func stringToBigInt(s string) *big.Int {
38+
bi, _ := new(big.Int).SetString(s, 10)
39+
return bi
40+
}
41+
3442
func evmToCosmosAddress(evmAddr string) (sdk.AccAddress, error) {
3543
if len(evmAddr) != 42 {
3644
return nil, fmt.Errorf("invalid EVM address length")
@@ -119,14 +127,19 @@ func (ms msgServer) DeployNMSC(ctx context.Context, msg *types.MsgDeployNMSC) (*
119127
if err != nil {
120128
return nil, err
121129
}
130+
122131
caipString := msg.CaipString
123132
ownerType := uint8(msg.OwnerType)
124133
factoryAddress := common.HexToAddress(adminParams.FactoryAddress)
125134
verifierPrecompile := common.HexToAddress(adminParams.VerifierPrecompile)
126135

136+
userKeys := common.HexToAddress("0x778D3206374f8AC265728E18E3fE2Ae6b93E4ce4").Bytes()
137+
fmt.Println("User key:", userKeys)
138+
127139
fmt.Println("Factory address:", factoryAddress)
128140
fmt.Println("Verifier precompile address:", verifierPrecompile)
129141
fmt.Println("User key:", userKey)
142+
fmt.Println(msg.UserKey)
130143
fmt.Println("CAIP string:", caipString)
131144
fmt.Println("Owner type:", ownerType)
132145
fmt.Println("EVM from address:", evmFromAddress)
@@ -247,3 +260,100 @@ func (ms msgServer) MintPush(ctx context.Context, msg *types.MsgMintPush) (*type
247260

248261
return &types.MsgMintPushResponse{}, nil
249262
}
263+
264+
// ExecutePayload implements types.MsgServer.
265+
func (ms msgServer) ExecutePayload(ctx context.Context, msg *types.MsgExecutePayload) (*types.MsgExecutePayloadResponse, error) {
266+
sdkCtx := sdk.UnwrapSDKContext(ctx)
267+
268+
// Retrieve the current Params
269+
adminParams, err := ms.k.AdminParams.Get(ctx)
270+
if err != nil {
271+
return nil, errors.Wrapf(err, "failed to get admin params")
272+
}
273+
274+
// Get the Cosmos address in Bech32 format (from the signer in MsgDeployNMSC)
275+
signer := msg.Signer
276+
277+
// Convert the Bech32 address to sdk.AccAddress
278+
cosmosAddr, err := sdk.AccAddressFromBech32(signer)
279+
if err != nil {
280+
return nil, errors.Wrapf(err, "failed to convert Bech32 address")
281+
}
282+
283+
// Now convert the Cosmos address to an EVM address
284+
evmFromAddress := common.BytesToAddress(cosmosAddr.Bytes()[len(cosmosAddr)-20:])
285+
factoryAddress := common.HexToAddress(adminParams.FactoryAddress)
286+
287+
// Parse ABI once
288+
parsedFactoryABI, err := abi.JSON(strings.NewReader(types.FactoryV1ABI))
289+
if err != nil {
290+
return nil, err
291+
}
292+
293+
// Calling factory contract to compute the smart account address
294+
receipt, err := ms.k.evmKeeper.CallEVM(
295+
sdkCtx,
296+
parsedFactoryABI,
297+
evmFromAddress, // who is sending the transaction
298+
factoryAddress, // destination: FactoryV1 contract
299+
false, // commit = false
300+
"computeSmartAccountAddress",
301+
msg.CaipString,
302+
)
303+
if err != nil {
304+
return nil, err
305+
}
306+
307+
if receipt.VmError != "" {
308+
fmt.Println("VM Error:", receipt.VmError)
309+
}
310+
311+
returnedBytesHex := common.Bytes2Hex(receipt.Ret)
312+
addressBytes := returnedBytesHex[24:] // last 20 bytes
313+
nmscComputedAddress := "0x" + addressBytes
314+
nmscAddr := common.HexToAddress(nmscComputedAddress)
315+
316+
parsedNMSCABI, err := abi.JSON(strings.NewReader(types.SmartAccountV1ABI))
317+
if err != nil {
318+
return nil, err
319+
}
320+
321+
protoPayload := msg.CrosschainPayload // your existing proto-generated struct
322+
323+
payload := types.AbiCrossChainPayload{
324+
Target: common.HexToAddress(protoPayload.Target),
325+
Value: stringToBigInt(protoPayload.Value),
326+
Data: protoPayload.Data,
327+
GasLimit: stringToBigInt(protoPayload.GasLimit),
328+
MaxFeePerGas: stringToBigInt(protoPayload.MaxFeePerGas),
329+
MaxPriorityFeePerGas: stringToBigInt(protoPayload.MaxPriorityFeePerGas),
330+
Nonce: stringToBigInt(protoPayload.Nonce),
331+
Deadline: stringToBigInt(protoPayload.Deadline),
332+
}
333+
334+
// Calling the NMSC contract
335+
receipt, err = ms.k.evmKeeper.CallEVM(
336+
sdkCtx,
337+
parsedNMSCABI,
338+
evmFromAddress, // who is sending the transaction
339+
nmscAddr, // destination: nmsc contract
340+
true, // commit = true
341+
"executePayload",
342+
payload,
343+
msg.Signature,
344+
)
345+
if err != nil {
346+
return nil, err
347+
}
348+
349+
fmt.Println("EVM tx hash:", receipt.Hash)
350+
fmt.Println("Gas used:", receipt.GasUsed)
351+
fmt.Println("Logs:", receipt.Logs)
352+
fmt.Println("Returned data:", receipt.Ret)
353+
if receipt.VmError != "" {
354+
fmt.Println("VM Error:", receipt.VmError)
355+
}
356+
fmt.Println("Return data:", common.Bytes2Hex(receipt.Ret))
357+
358+
return &types.MsgExecutePayloadResponse{}, nil
359+
}

0 commit comments

Comments
 (0)