From adb8e80b27851c085a9503849267b597feb8c33e Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Wed, 4 Dec 2024 13:51:27 -0500 Subject: [PATCH 01/24] feat: copying for alonso --- cmd/ulxly/BridgeAssetUsage.md | 61 ++ cmd/ulxly/BridgeMessageUsage.md | 53 ++ cmd/ulxly/BridgeWETHMessageUsage.md | 55 ++ cmd/ulxly/ClaimAssetUsage.md | 76 ++ cmd/ulxly/ClaimMessageUsage.md | 57 ++ cmd/ulxly/delete.md | 70 ++ cmd/ulxly/ulxly.go | 1141 +++++++++++++++++---------- go.mod | 4 + go.sum | 6 + 9 files changed, 1085 insertions(+), 438 deletions(-) create mode 100644 cmd/ulxly/BridgeAssetUsage.md create mode 100644 cmd/ulxly/BridgeMessageUsage.md create mode 100644 cmd/ulxly/BridgeWETHMessageUsage.md create mode 100644 cmd/ulxly/ClaimAssetUsage.md create mode 100644 cmd/ulxly/ClaimMessageUsage.md create mode 100644 cmd/ulxly/delete.md diff --git a/cmd/ulxly/BridgeAssetUsage.md b/cmd/ulxly/BridgeAssetUsage.md new file mode 100644 index 000000000..eac962d79 --- /dev/null +++ b/cmd/ulxly/BridgeAssetUsage.md @@ -0,0 +1,61 @@ +This command will attempt to send a deposit transaction to the bridge contract. + +```solidity + /** + * @notice Deposit add a new leaf to the merkle tree + * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call + * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. + * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens + * do not call any external address in that case + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param token Token address, 0 address is reserved for ether + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param permitData Raw data of the call `permit` of the token + */ + function bridgeAsset( + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + address token, + bool forceUpdateGlobalExitRoot, + bytes calldata permitData + ); + +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly bridge-asset \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --gas-limit 300000 \ + --amount 1000000000000000000 \ + --rpc-url http://127.0.0.1:8545 \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --destination-network 1 \ + --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 +``` + +This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +``` + +Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command + + +Failed deposit transactions will output logs like below: + +```bash +Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 +Try increasing the gas limit: +Current gas limit: 100000 +Cumulative gas used for transaction: 98641 +``` + +The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. diff --git a/cmd/ulxly/BridgeMessageUsage.md b/cmd/ulxly/BridgeMessageUsage.md new file mode 100644 index 000000000..77aa8dced --- /dev/null +++ b/cmd/ulxly/BridgeMessageUsage.md @@ -0,0 +1,53 @@ +This command will attempt to send a deposit transaction to the bridge contract. + +```solidity + /** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ + function bridgeMessage( + uint32 destinationNetwork, + address destinationAddress, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata + ); +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly bridge-message \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --gas-limit 300000 \ + --amount 1000000000000000000 \ + --rpc-url http://127.0.0.1:8545 \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --destination-network 1 \ + --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 + --call-data 0x001010109200090028979743971976836486868648629808961824738090896826764980866fac97863898ca08928fc7279643 +``` + +This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +``` + +Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command + + +Failed deposit transactions will output logs like below: + +```bash +Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 +Try increasing the gas limit: +Current gas limit: 100000 +Cumulative gas used for transaction: 98641 +``` + +The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. diff --git a/cmd/ulxly/BridgeWETHMessageUsage.md b/cmd/ulxly/BridgeWETHMessageUsage.md new file mode 100644 index 000000000..5bc7d8097 --- /dev/null +++ b/cmd/ulxly/BridgeWETHMessageUsage.md @@ -0,0 +1,55 @@ +This command will attempt to send a deposit transaction to the bridge contract. + +```solidity + /** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amountWETH Amount of WETH tokens + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ + function bridgeMessageWETH( + uint32 destinationNetwork, + address destinationAddress, + uint256 amountWETH, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata + ); +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly bridge-message-weth \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --gas-limit 300000 \ + --amount 1000000000000000000 \ + --rpc-url http://127.0.0.1:8545 \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --destination-network 1 \ + --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 + --call-data 0x001010109200090028979743971976836486868648629808961824738090896826764980866fac97863898ca08928fc7279643 +``` + +This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +``` + +Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command + + +Failed deposit transactions will output logs like below: + +```bash +Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 +Try increasing the gas limit: +Current gas limit: 100000 +Cumulative gas used for transaction: 98641 +``` + +The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. diff --git a/cmd/ulxly/ClaimAssetUsage.md b/cmd/ulxly/ClaimAssetUsage.md new file mode 100644 index 000000000..9c53af434 --- /dev/null +++ b/cmd/ulxly/ClaimAssetUsage.md @@ -0,0 +1,76 @@ +This command will attempt to send a claim transaction to the bridge contract. + +```solidity + /** + * @notice Verify merkle proof and withdraw tokens/ether + * @param smtProofLocalExitRoot Smt proof to proof the leaf against the network exit root + * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root + * @param globalIndex Global index is defined as: + * | 191 bits | 1 bit | 32 bits | 32 bits | + * | 0 | mainnetFlag | rollupIndex | localRootIndex | + * note that only the rollup index will be used only in case the mainnet flag is 0 + * note that global index do not assert the unused bits to 0. + * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract + * to avoid possible synch attacks + * @param mainnetExitRoot Mainnet exit root + * @param rollupExitRoot Rollup exit root + * @param originNetwork Origin network + * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param metadata Abi encoded metadata if any, empty otherwise + */ + function claimAsset( + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originTokenAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata + ); + +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly deposit-claim \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --claim-index 0 \ + --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ + --claim-network 0 \ + --rpc-url http://127.0.0.1:32790 \ + --bridge-service-url http://127.0.0.1:32804 +``` + +This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b +``` + +Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` + + +Failed deposit transactions will output logs like below: + +```bash +Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a +``` + +The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: + +```! +curl http://127.0.0.1:32790 \ +-X POST \ +-H "Content-Type: application/json" \ +--data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' +``` diff --git a/cmd/ulxly/ClaimMessageUsage.md b/cmd/ulxly/ClaimMessageUsage.md new file mode 100644 index 000000000..a29823191 --- /dev/null +++ b/cmd/ulxly/ClaimMessageUsage.md @@ -0,0 +1,57 @@ +This command will attempt to send a claim transaction to the bridge contract. + +```solidity + /** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ + function bridgeMessage( + uint32 destinationNetwork, + address destinationAddress, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata + ); + +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly deposit-claim \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --claim-index 0 \ + --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ + --claim-network 0 \ + --rpc-url http://127.0.0.1:32790 \ + --bridge-service-url http://127.0.0.1:32804 +``` + +This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b +``` + +Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` + + +Failed deposit transactions will output logs like below: + +```bash +Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a +``` + +The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: + +```! +curl http://127.0.0.1:32790 \ +-X POST \ +-H "Content-Type: application/json" \ +--data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' +``` diff --git a/cmd/ulxly/delete.md b/cmd/ulxly/delete.md new file mode 100644 index 000000000..7c9c96e99 --- /dev/null +++ b/cmd/ulxly/delete.md @@ -0,0 +1,70 @@ +This command will attempt to send a deposit transaction to the bridge contract. + +```solidity + /** + * @notice Deposit add a new leaf to the merkle tree + * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call + * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. + * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens + * do not call any external address in that case + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param token Token address, 0 address is reserved for ether + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param permitData Raw data of the call `permit` of the token + */ + function bridgeAsset( + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + address token, + bool forceUpdateGlobalExitRoot, + bytes calldata permitData + ); + +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly deposit-new \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --gas-limit 300000 \ + --amount 1000000000000000000 \ + --rpc-url http://127.0.0.1:8545 \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --destination-network 1 \ + --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 +``` +go run ulxly.go ulxly bridge-asset --private-key 846f556e5509c36b5756fa3741009310908d606db18d5916d43e6c7d22e0f5a7 --gas-limit 300000 --rpc-url https://sepolia.infura.io/v3/7c490aa772fa466293ee1ac62761330a --bridge-address 0x1348947e282138d8f377b467f7d9c2eb0f335d1f --destination-network 1 --amount 19 + +go run main.go ulxly bridge-message --private-key 846f556e5509c36b5756fa3741009310908d606db18d5916d43e6c7d22e0f5a7 --gas-limit 300000 --rpc-url https://sepolia.infura.io/v3/7c490aa772fa466293ee1ac62761330a --bridge-address 0x1348947e282138d8f377b467f7d9c2eb0f335d1f --destination-network 1 --amount 19 --call-data 0x18976546789087654356789654345678976543567897654356789765435468797865435468797654354678907654356879765436798765435467986543 + +go run main.go ulxly claim-asset --private-key 846f556e5509c36b5756fa3741009310908d606db18d5916d43e6c7d22e0f5a7 --gas-limit 30000000 --rpc-url https://sepolia.infura.io/v3/7c490aa772fa466293ee1ac62761330a --bridge-address 0x1348947e282138d8f377b467f7d9c2eb0f335d1f --claim-address 0x2536C2745Ac4A584656A830f7bdCd329c94e8F30 --claim-index 7780 --bridge-service-url https://bridge-api.internal.zkevm-rpc.com --deposit-network 1 + +go run main.go ulxly claim-message --private-key 846f556e5509c36b5756fa3741009310908d606db18d5916d43e6c7d +22e0f5a7 --gas-limit 300000 --rpc-url https://sepolia.infura.io/v3/7c490aa772fa466293ee1ac62761330a --bridge-address 0x1348947e282138d8f377b467f7d9c2eb0f335d1f --claim-address 0x2536C2745Ac4A584656A830f7bdCd329c94e8F30 --claim-index 7780 --call-data 0x18976546789087654356789654345678976543567897654356789765435468797865435468797654354678907654356879765436798765435467986543 --bridge-service-url https://bridge-api.internal.zkevm-rpc.com + + +This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +``` + +Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command + + +Failed deposit transactions will output logs like below: + +```bash +Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 +Try increasing the gas limit: +Current gas limit: 100000 +Cumulative gas used for transaction: 98641 +``` + +The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 4a008d4d1..7ea04e687 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "context" - "crypto/ecdsa" _ "embed" "encoding/binary" "encoding/json" @@ -14,7 +13,6 @@ import ( "math/big" "net/http" "os" - "strconv" "strings" "time" @@ -29,6 +27,7 @@ import ( "github.com/0xPolygon/polygon-cli/bindings/ulxly" "github.com/rs/zerolog/log" "github.com/spf13/cobra" + "github.com/urfave/cli/v2" ) const ( @@ -53,6 +52,7 @@ type uLxLyArgs struct { BridgeServiceRPCURL *string ClaimRPCURL *string ClaimPrivateKey *string + NetworkID *uint32 ClaimBridgeAddress *string ClaimGasLimit *uint64 ClaimChainID *string @@ -102,371 +102,409 @@ type BridgeProof struct { } `json:"proof"` } -type BridgeDeposits struct { - Deposit []struct { - LeafType int `json:"leaf_type"` - OrigNet int `json:"orig_net"` +type BridgeDeposit struct { + Deposit struct { + LeafType uint8 `json:"leaf_type"` + OrigNet uint32 `json:"orig_net"` OrigAddr string `json:"orig_addr"` Amount string `json:"amount"` - DestNet int `json:"dest_net"` + DestNet uint32 `json:"dest_net"` DestAddr string `json:"dest_addr"` BlockNum string `json:"block_num"` - DepositCnt string `json:"deposit_cnt"` - NetworkID int `json:"network_id"` + DepositCnt uint32 `json:"deposit_cnt"` + NetworkID uint32 `json:"network_id"` TxHash string `json:"tx_hash"` ClaimTxHash string `json:"claim_tx_hash"` Metadata string `json:"metadata"` ReadyForClaim bool `json:"ready_for_claim"` GlobalIndex string `json:"global_index"` - } `json:"deposits"` - TotalCnt string `json:"total_cnt"` + } `json:"deposit"` + Code *int `json:"code"` + Message *string `json:"message"` } -var ulxlyInputArgs uLxLyArgs - var ULxLyCmd = &cobra.Command{ - Use: "ulxly", - Short: "Utilities for interacting with the lxly bridge", - Long: "These are low level tools for directly scanning bridge events and constructing proofs.", - Args: cobra.NoArgs, + Use: "ulxly", + Short: "Utilities for interacting with the lxly bridge", + Long: "These are low level tools for directly scanning bridge events and constructing proofs.", + DisableFlagParsing: true, + Run: initCli, } -//go:embed depositGetUsage.md -var depositGetUsage string -var depositGetCmd = &cobra.Command{ - Use: "deposit-get", - Short: "Get a range of deposits", - Long: depositGetUsage, - Args: cobra.NoArgs, - PreRunE: checkGetDepositArgs, - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - // Dial the Ethereum RPC server. - rpc, err := ethrpc.DialContext(ctx, *ulxlyInputArgs.RPCURL) - if err != nil { - log.Error().Err(err).Msg("Unable to Dial RPC") - return err +func readDeposit(ctx *cli.Context) error { + bridgeAddress := ctx.String(bridgeAddressFlag.Name) + rpcUrl := ctx.String(rpcURLFlag.Name) + toBlock := ctx.Uint64(toBlockFlag.Name) + fromBlock := ctx.Uint64(fromBlockFlag.Name) + filter := ctx.Uint64(filterFlag.Name) + // Dial the Ethereum RPC server. + rpc, err := ethrpc.DialContext(ctx.Context, rpcUrl) + if err != nil { + log.Error().Err(err).Msg("Unable to Dial RPC") + return err + } + defer rpc.Close() + ec := ethclient.NewClient(rpc) + + bridgeV2, err := ulxly.NewUlxly(common.HexToAddress(bridgeAddress), ec) + if err != nil { + return err + } + currentBlock := fromBlock + for currentBlock < toBlock { + endBlock := currentBlock + filter + if endBlock > toBlock { + endBlock = toBlock } - defer rpc.Close() - ec := ethclient.NewClient(rpc) - bridgeV2, err := ulxly.NewUlxly(common.HexToAddress(*ulxlyInputArgs.BridgeAddress), ec) + opts := bind.FilterOpts{ + Start: currentBlock, + End: &endBlock, + Context: ctx.Context, + } + evtV2Iterator, err := bridgeV2.FilterBridgeEvent(&opts) if err != nil { return err } - fromBlock := *ulxlyInputArgs.FromBlock - toBlock := *ulxlyInputArgs.ToBlock - currentBlock := fromBlock - for currentBlock < toBlock { - endBlock := currentBlock + *ulxlyInputArgs.FilterSize - if endBlock > toBlock { - endBlock = toBlock - } - opts := bind.FilterOpts{ - Start: currentBlock, - End: &endBlock, - Context: ctx, - } - evtV2Iterator, err := bridgeV2.FilterBridgeEvent(&opts) + for evtV2Iterator.Next() { + evt := evtV2Iterator.Event + log.Info().Uint32("deposit", evt.DepositCount).Uint64("block-number", evt.Raw.BlockNumber).Msg("Found ulxly Deposit") + var jBytes []byte + jBytes, err = json.Marshal(evt) if err != nil { return err } - - for evtV2Iterator.Next() { - evt := evtV2Iterator.Event - log.Info().Uint32("deposit", evt.DepositCount).Uint64("block-number", evt.Raw.BlockNumber).Msg("Found ulxly Deposit") - var jBytes []byte - jBytes, err = json.Marshal(evt) - if err != nil { - return err - } - fmt.Println(string(jBytes)) - } - err = evtV2Iterator.Close() - if err != nil { - log.Error().Err(err).Msg("error closing event iterator") - } - currentBlock = endBlock + fmt.Println(string(jBytes)) } - - return nil - }, -} - -//go:embed depositNewUsage.md -var depositNewUsage string -var depositNewCmd = &cobra.Command{ - Use: "deposit-new", - Short: "Make a uLxLy deposit transaction", - Long: depositNewUsage, - Args: cobra.NoArgs, - PreRunE: checkDepositArgs, - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - // Dial the Ethereum RPC server. - client, err := ethclient.DialContext(ctx, *ulxlyInputArgs.DepositRPCURL) + err = evtV2Iterator.Close() if err != nil { - log.Error().Err(err).Msg("Unable to Dial RPC") - return err + log.Error().Err(err).Msg("error closing event iterator") } - defer client.Close() - // Initialize and assign variables required to send transaction payload - bridgeV2, privateKey, fromAddress, gasLimit, gasPrice, toAddress, signer := generateTransactionPayload(ctx, client, *ulxlyInputArgs.DepositBridgeAddress, *ulxlyInputArgs.DepositPrivateKey, *ulxlyInputArgs.DepositGasLimit, *ulxlyInputArgs.DestinationAddress, *ulxlyInputArgs.DepositChainID) + currentBlock = endBlock + } - value := big.NewInt(*ulxlyInputArgs.Amount) - tokenAddress := common.HexToAddress(*ulxlyInputArgs.TokenAddress) - callData := common.Hex2Bytes(*ulxlyInputArgs.CallData) + return nil +} - tops := &bind.TransactOpts{ - Signer: func(address common.Address, transaction *types.Transaction) (*types.Transaction, error) { - return types.SignTx(transaction, signer, privateKey) - }, - From: fromAddress, - Context: ctx, - GasLimit: gasLimit, - GasPrice: gasPrice, - GasFeeCap: nil, - GasTipCap: nil, - } - if tokenAddress == common.HexToAddress("0x0000000000000000000000000000000000000000") { - tops = &bind.TransactOpts{ - Signer: func(address common.Address, transaction *types.Transaction) (*types.Transaction, error) { - return types.SignTx(transaction, signer, privateKey) - }, - Value: value, - From: fromAddress, - Context: ctx, - GasLimit: gasLimit, - GasPrice: gasPrice, - GasFeeCap: nil, - GasTipCap: nil, - } - } +func proof(ctx *cli.Context) error { + depositNumber := ctx.Uint64(depositNumberFlag.Name) + rawDepositData, err := getInputData(ctx) + if err != nil { + return err + } + return readDeposits(rawDepositData, uint32(depositNumber)) +} - var bridgeTxn *types.Transaction - switch { - case *ulxlyInputArgs.DepositMessage: - bridgeTxn, err = bridgeV2.BridgeMessage(tops, *ulxlyInputArgs.DestinationNetwork, toAddress, *ulxlyInputArgs.IsForced, callData) - if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err - } - case *ulxlyInputArgs.DepositWETH: - bridgeTxn, err = bridgeV2.BridgeMessageWETH(tops, *ulxlyInputArgs.DestinationNetwork, toAddress, value, *ulxlyInputArgs.IsForced, callData) - if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err - } - default: - bridgeTxn, err = bridgeV2.BridgeAsset(tops, *ulxlyInputArgs.DestinationNetwork, toAddress, value, tokenAddress, *ulxlyInputArgs.IsForced, callData) - if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err - } - } +func emptyProof(ctx *cli.Context) error { + p := new(Proof) - // Wait for the transaction to be mined - // TODO: Consider creating a function for this section - txnMinedTimer := time.NewTimer(time.Duration(*ulxlyInputArgs.DepositTimeoutTxnReceipt) * time.Second) - defer txnMinedTimer.Stop() - for { - select { - case <-txnMinedTimer.C: - log.Info().Msg("Wait timer for transaction receipt exceeded!") - return nil - default: - r, err := client.TransactionReceipt(ctx, bridgeTxn.Hash()) - if err != nil { - if err.Error() != "not found" { - log.Error().Err(err) - return err - } - time.Sleep(1 * time.Second) - continue - } - if r.Status != 0 { - log.Info().Interface("txHash", r.TxHash).Msg("Deposit transaction successful") - return nil - } else if r.Status == 0 { - log.Error().Interface("txHash", r.TxHash).Msg("Deposit transaction failed") - log.Info().Uint64("currentGasLimit", gasLimit).Uint64("cumulativeGasUsedForTx", r.CumulativeGasUsed).Msg("Perhaps try increasing the gas limit") - return nil - } - time.Sleep(1 * time.Second) - } - } - }, -} - -//go:embed depositClaimUsage.md -var depositClaimUsage string -var depositClaimCmd = &cobra.Command{ - Use: "deposit-claim", - Short: "Make a uLxLy claim transaction", - Long: depositClaimUsage, - Args: cobra.NoArgs, - PreRunE: checkClaimArgs, - RunE: func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - // Dial Ethereum client - client, err := ethclient.DialContext(ctx, *ulxlyInputArgs.ClaimRPCURL) - if err != nil { - log.Error().Err(err).Msg("Unable to Dial RPC") - return err - } - defer client.Close() - // Initialize and assign variables required to send transaction payload - bridgeV2, privateKey, fromAddress, gasLimit, gasPrice, toAddress, signer := generateTransactionPayload(ctx, client, *ulxlyInputArgs.ClaimBridgeAddress, *ulxlyInputArgs.ClaimPrivateKey, *ulxlyInputArgs.ClaimGasLimit, *ulxlyInputArgs.ClaimAddress, *ulxlyInputArgs.ClaimChainID) + e := generateEmptyHashes(TreeDepth) + copy(p.Siblings[:], e) + fmt.Println(p.String()) + return nil +} - // Call the bridge service RPC URL to get the merkle proofs and exit roots and parses them to the correct formats. - bridgeServiceProofEndpoint := fmt.Sprintf("%s/merkle-proof?deposit_cnt=%s&net_id=%s", *ulxlyInputArgs.BridgeServiceRPCURL, *ulxlyInputArgs.ClaimIndex, *ulxlyInputArgs.ClaimOriginNetwork) - merkleProofArray, rollupMerkleProofArray, mainExitRoot, rollupExitRoot := getMerkleProofsExitRoots(bridgeServiceProofEndpoint) +func zeroProof(ctx *cli.Context) error { + p := new(Proof) - tops := &bind.TransactOpts{ - Signer: func(address common.Address, transaction *types.Transaction) (*types.Transaction, error) { - return types.SignTx(transaction, signer, privateKey) - }, - // Value: value, - From: fromAddress, - Context: ctx, - GasLimit: gasLimit, - GasPrice: gasPrice, - GasFeeCap: nil, - GasTipCap: nil, - } + e := generateZeroHashes(TreeDepth) + copy(p.Siblings[:], e) + fmt.Println(p.String()) + return nil +} - // Call the bridge service RPC URL to get the deposits data and parses them to the correct formats. - bridgeServiceDepositsEndpoint := fmt.Sprintf("%s/bridges/%s", *ulxlyInputArgs.BridgeServiceRPCURL, *ulxlyInputArgs.ClaimAddress) - globalIndex, originAddress, amount, metadata, err := getDeposits(bridgeServiceDepositsEndpoint) - if err != nil { - log.Error().Err(err) - return err - } +func bridgeAsset(ctx *cli.Context) error { + bridgeAddress := ctx.String(bridgeAddressFlag.Name) + privateKey := ctx.String(privKeyFlag.Name) + gasLimit := ctx.Uint64(gasLimitFlag.Name) + destinationAddress := ctx.String(destAddressFlag.Name) + chainID := ctx.String(chainIDFlag.Name) + amount := ctx.String(AmountFlag.Name) + tokenAddr := ctx.String(tokenAddressFlag.Name) + callDataString := ctx.String(callDataFlag.Name) + destinationNetwork := uint32(ctx.Uint(destNetworkFlag.Name)) + isForced := ctx.Bool(forceFlag.Name) + timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) + RPCURL := ctx.String(rpcURLFlag.Name) + + // Dial the Ethereum RPC server. + client, err := ethclient.DialContext(ctx.Context, RPCURL) + if err != nil { + log.Error().Err(err).Msg("Unable to Dial RPC") + return err + } + defer client.Close() + // Initialize and assign variables required to send transaction payload + bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + if err != nil { + log.Error().Err(err).Msg("error generating transaction payload") + return err + } - claimOriginNetwork, _ := strconv.Atoi(*ulxlyInputArgs.ClaimOriginNetwork) // Convert ClaimOriginNetwork to int - claimDestinationNetwork, _ := strconv.Atoi(*ulxlyInputArgs.ClaimDestinationNetwork) // Convert ClaimDestinationNetwork to int - var claimTxn *types.Transaction - switch { - case *ulxlyInputArgs.ClaimMessage: - claimTxn, err = bridgeV2.ClaimMessage(tops, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), uint32(claimOriginNetwork), originAddress, uint32(claimDestinationNetwork), toAddress, amount, metadata) - if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err - } + value, _ := big.NewInt(0).SetString(amount, 0) + tokenAddress := common.HexToAddress(tokenAddr) + callData := common.Hex2Bytes(callDataString) + + if tokenAddress == common.HexToAddress("0x0000000000000000000000000000000000000000") { + auth.Value = value + } + + bridgeTxn, err := bridgeV2.BridgeAsset(auth, destinationNetwork, toAddress, value, tokenAddress, isForced, callData) + if err != nil { + log.Error().Err(err).Msg("Unable to interact with bridge contract") + return err + } + log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) + return WaitMineTransaction(ctx.Context, client, bridgeTxn, timeoutTxnReceipt) +} + +func bridgeMessage(ctx *cli.Context) error { + bridgeAddress := ctx.String(bridgeAddressFlag.Name) + privateKey := ctx.String(privKeyFlag.Name) + gasLimit := ctx.Uint64(gasLimitFlag.Name) + destinationAddress := ctx.String(destAddressFlag.Name) + chainID := ctx.String(chainIDFlag.Name) + amount := ctx.String(AmountFlag.Name) + tokenAddr := ctx.String(tokenAddressFlag.Name) + callDataString := ctx.String(callDataFlag.Name) + destinationNetwork := uint32(ctx.Uint(destNetworkFlag.Name)) + isForced := ctx.Bool(forceFlag.Name) + timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) + RPCURL := ctx.String(rpcURLFlag.Name) + + // Dial the Ethereum RPC server. + client, err := ethclient.DialContext(ctx.Context, RPCURL) + if err != nil { + log.Error().Err(err).Msg("Unable to Dial RPC") + return err + } + defer client.Close() + // Initialize and assign variables required to send transaction payload + bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + if err != nil { + log.Error().Err(err).Msg("error generating transaction payload") + return err + } + + value, _ := big.NewInt(0).SetString(amount, 0) + tokenAddress := common.HexToAddress(tokenAddr) + callData := common.Hex2Bytes(callDataString) + + if tokenAddress == common.HexToAddress("0x0000000000000000000000000000000000000000") { + auth.Value = value + } + + bridgeTxn, err := bridgeV2.BridgeMessage(auth, destinationNetwork, toAddress, isForced, callData) + if err != nil { + log.Error().Err(err).Msg("Unable to interact with bridge contract") + return err + } + log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) + return WaitMineTransaction(ctx.Context, client, bridgeTxn, timeoutTxnReceipt) +} + +func bridgeWETHMessage(ctx *cli.Context) error { + bridgeAddress := ctx.String(bridgeAddressFlag.Name) + privateKey := ctx.String(privKeyFlag.Name) + gasLimit := ctx.Uint64(gasLimitFlag.Name) + destinationAddress := ctx.String(destAddressFlag.Name) + chainID := ctx.String(chainIDFlag.Name) + amount := ctx.String(AmountFlag.Name) + callDataString := ctx.String(callDataFlag.Name) + destinationNetwork := uint32(ctx.Uint(destNetworkFlag.Name)) + isForced := ctx.Bool(forceFlag.Name) + timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) + RPCURL := ctx.String(rpcURLFlag.Name) + // Dial the Ethereum RPC server. + client, err := ethclient.DialContext(ctx.Context, RPCURL) + if err != nil { + log.Error().Err(err).Msg("Unable to Dial RPC") + return err + } + defer client.Close() + // Initialize and assign variables required to send transaction payload + bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + if err != nil { + log.Error().Err(err).Msg("error generating transaction payload") + return err + } + // Check if WETH is allowed + wethAddress, err := bridgeV2.WETHToken(&bind.CallOpts{Pending: false}) + if err != nil { + log.Error().Err(err).Msg("error getting WETH address from the bridge smc") + return err + } + if wethAddress == (common.Address{}) { + return fmt.Errorf("bridge WETH not allowed. Native ETH token configured in this network. This tx will fail") + } + + value, _ := big.NewInt(0).SetString(amount, 0) + callData := common.Hex2Bytes(callDataString) + + bridgeTxn, err := bridgeV2.BridgeMessageWETH(auth, destinationNetwork, toAddress, value, isForced, callData) + if err != nil { + log.Error().Err(err).Msg("Unable to interact with bridge contract") + return err + } + log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) + return WaitMineTransaction(ctx.Context, client, bridgeTxn, timeoutTxnReceipt) +} + +func claimAsset(ctx *cli.Context) error { + bridgeAddress := ctx.String(bridgeAddressFlag.Name) + privateKey := ctx.String(privKeyFlag.Name) + gasLimit := ctx.Uint64(gasLimitFlag.Name) + destinationAddress := ctx.String(destAddressFlag.Name) + chainID := ctx.String(chainIDFlag.Name) + timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) + RPCURL := ctx.String(rpcURLFlag.Name) + depositCount := ctx.Uint64(depositCountFlag.Name) + depositNetwork := ctx.Uint64(depositNetworkFlag.Name) + bridgeServiceUrl := ctx.String(bridgeServiceUrlFlag.Name) + + // Dial Ethereum client + client, err := ethclient.DialContext(ctx.Context, RPCURL) + if err != nil { + log.Error().Err(err).Msg("Unable to Dial RPC") + return err + } + defer client.Close() + // Initialize and assign variables required to send transaction payload + bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + if err != nil { + log.Error().Err(err).Msg("error generating transaction payload") + return err + } + + ///////////////////////////////////////// TODO BORRAR + // gasPrice, err := client.SuggestGasPrice(ctx) // This call is done automatically if it is not set + // if err != nil { + // log.Error().Err(err).Msg("Cannot get suggested gas price") + // } + // auth.GasPrice = big.NewInt(0).Mul(gasPrice,big.NewInt(10)) + ///////////////////////////////////////////////////////// + + // Call the bridge service RPC URL to get the merkle proofs and exit roots and parses them to the correct formats. + bridgeServiceProofEndpoint := fmt.Sprintf("%s/merkle-proof?deposit_cnt=%d&net_id=%d", bridgeServiceUrl, depositCount, depositNetwork) + merkleProofArray, rollupMerkleProofArray, mainExitRoot, rollupExitRoot := getMerkleProofsExitRoots(bridgeServiceProofEndpoint) + + // Call the bridge service RPC URL to get the deposits data and parses them to the correct formats. + bridgeServiceDepositsEndpoint := fmt.Sprintf("%s/bridge?net_id=%d&deposit_cnt=%d", bridgeServiceUrl, depositNetwork, depositCount) + globalIndex, originAddress, amount, metadata, leafType, claimDestNetwork, claimOriginalNetwork, err := getDeposit(bridgeServiceDepositsEndpoint) + if err != nil { + log.Error().Err(err) + return err + } + if leafType != 0 { + log.Warn().Msg("Deposit leafType is not asset") + } + + claimTxn, err := bridgeV2.ClaimAsset(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) + if err != nil { + log.Error().Err(err).Msg("Unable to interact with bridge contract") + return err + } + log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) + return WaitMineTransaction(ctx.Context, client, claimTxn, timeoutTxnReceipt) +} + +func claimMessage(ctx *cli.Context) error { + bridgeAddress := ctx.String(bridgeAddressFlag.Name) + privateKey := ctx.String(privKeyFlag.Name) + gasLimit := ctx.Uint64(gasLimitFlag.Name) + destinationAddress := ctx.String(destAddressFlag.Name) + chainID := ctx.String(chainIDFlag.Name) + timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) + RPCURL := ctx.String(rpcURLFlag.Name) + depositCount := ctx.Uint64(depositCountFlag.Name) + depositNetwork := ctx.Uint64(depositNetworkFlag.Name) + bridgeServiceUrl := ctx.String(bridgeServiceUrlFlag.Name) + + // Dial Ethereum client + client, err := ethclient.DialContext(ctx.Context, RPCURL) + if err != nil { + log.Error().Err(err).Msg("Unable to Dial RPC") + return err + } + defer client.Close() + // Initialize and assign variables required to send transaction payload + bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + if err != nil { + log.Error().Err(err).Msg("error generating transaction payload") + return err + } + + // Call the bridge service RPC URL to get the merkle proofs and exit roots and parses them to the correct formats. + bridgeServiceProofEndpoint := fmt.Sprintf("%s/merkle-proof?deposit_cnt=%d&net_id=%d", bridgeServiceUrl, depositCount, depositNetwork) + merkleProofArray, rollupMerkleProofArray, mainExitRoot, rollupExitRoot := getMerkleProofsExitRoots(bridgeServiceProofEndpoint) + + // Call the bridge service RPC URL to get the deposits data and parses them to the correct formats. + bridgeServiceDepositsEndpoint := fmt.Sprintf("%s/bridge?net_id=%d&deposit_cnt=%d", bridgeServiceUrl, depositNetwork, depositCount) + globalIndex, originAddress, amount, metadata, leafType, claimDestNetwork, claimOriginalNetwork, err := getDeposit(bridgeServiceDepositsEndpoint) + if err != nil { + log.Error().Err(err) + return err + } + if leafType != 1 { + log.Warn().Msg("Deposit leafType is not message") + } + + claimTxn, err := bridgeV2.ClaimMessage(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) + if err != nil { + log.Error().Err(err).Msg("Unable to interact with bridge contract") + return err + } + log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) + return WaitMineTransaction(ctx.Context, client, claimTxn, timeoutTxnReceipt) +} + +// Wait for the transaction to be mined +func WaitMineTransaction(ctx context.Context, client *ethclient.Client, tx *types.Transaction, txTimeout uint64) error { + txnMinedTimer := time.NewTimer(time.Duration(txTimeout) * time.Second) + defer txnMinedTimer.Stop() + for { + select { + case <-txnMinedTimer.C: + log.Info().Msg("Wait timer for transaction receipt exceeded!") + return nil default: - claimTxn, err = bridgeV2.ClaimAsset(tops, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), uint32(claimOriginNetwork), originAddress, uint32(claimDestinationNetwork), toAddress, amount, metadata) + r, err := client.TransactionReceipt(ctx, tx.Hash()) if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err - } - } - - // Wait for the transaction to be mined - // TODO: Consider creating a function for this section - txnMinedTimer := time.NewTimer(time.Duration(*ulxlyInputArgs.ClaimTimeoutTxnReceipt) * time.Second) - defer txnMinedTimer.Stop() - for { - select { - case <-txnMinedTimer.C: - log.Info().Msg("Wait timer for transaction receipt exceeded!") - return nil - default: - r, err := client.TransactionReceipt(ctx, claimTxn.Hash()) - if err != nil { - if err.Error() != "not found" { - log.Error().Err(err) - return err - } - time.Sleep(1 * time.Second) - continue - } - if r.Status != 0 { - log.Info().Interface("txHash", r.TxHash).Msg("Claim transaction successful") - return nil - } else if r.Status == 0 { - log.Info().Interface("txHash", r.TxHash).Msg("Claim transaction failed") - return nil + if err.Error() != "not found" { + log.Error().Err(err) + return err } time.Sleep(1 * time.Second) + continue } + if r.Status != 0 { + log.Info().Interface("txHash", r.TxHash).Msg("Deposit transaction successful") + return nil + } else if r.Status == 0 { + log.Error().Interface("txHash", r.TxHash).Msg("Deposit transaction failed") + log.Info().Uint64("GasUsed", tx.Gas()).Uint64("cumulativeGasUsedForTx", r.CumulativeGasUsed).Msg("Perhaps try increasing the gas limit") + return nil + } + time.Sleep(1 * time.Second) } - }, + } } -//go:embed proofUsage.md -var proofUsage string -var ProofCmd = &cobra.Command{ - Use: "proof", - Short: "generate a merkle proof", - Long: proofUsage, - Args: cobra.NoArgs, - PreRunE: checkProofArgs, - RunE: func(cmd *cobra.Command, args []string) error { - rawDepositData, err := getInputData(cmd, args) - if err != nil { - return err - } - return readDeposits(rawDepositData) - }, -} - -var EmptyProofCmd = &cobra.Command{ - Use: "empty-proof", - Short: "print an empty proof structure", - Long: `Use this command to print an empty proof response that's filled with -zero-valued siblings like -0x0000000000000000000000000000000000000000000000000000000000000000. This -can be useful when you need to submit a dummy proof.`, - Args: cobra.NoArgs, - PreRunE: checkProofArgs, - RunE: func(cmd *cobra.Command, args []string) error { - p := new(Proof) - - e := generateEmptyHashes(TreeDepth) - copy(p.Siblings[:], e) - fmt.Println(p.String()) - return nil - }, -} - -var ZeroProofCmd = &cobra.Command{ - Use: "zero-proof", - Short: "print a proof structure with the zero hashes", - Long: `Use this command to print a proof response that's filled with the zero -hashes. This values are very helpful for debugging because it would -tell you how populated the tree is and roughly which leaves and -siblings are empty. It's also helpful for sanity checking a proof -response to understand if the hashed value is part of the zero hashes -or if it's actually an intermediate hash.`, - Args: cobra.NoArgs, - PreRunE: checkProofArgs, - RunE: func(cmd *cobra.Command, args []string) error { - p := new(Proof) - - e := generateZeroHashes(TreeDepth) - copy(p.Siblings[:], e) - fmt.Println(p.String()) - return nil - }, -} - -func checkProofArgs(cmd *cobra.Command, args []string) error { - return nil -} -func getInputData(_ *cobra.Command, args []string) ([]byte, error) { - if ulxlyInputArgs.InputFileName != nil && *ulxlyInputArgs.InputFileName != "" { - return os.ReadFile(*ulxlyInputArgs.InputFileName) +func getInputData(ctx *cli.Context) ([]byte, error) { + fileName := ctx.String(inputFileNameFlag.Name) + if fileName != "" { + return os.ReadFile(fileName) } - if len(args) > 1 { - concat := strings.Join(args[1:], " ") + if ctx.Args().Len() > 1 { + concat := strings.Join(ctx.Args().Slice()[1:], " ") return []byte(concat), nil } return io.ReadAll(os.Stdin) } -func readDeposits(rawDeposits []byte) error { +func readDeposits(rawDeposits []byte, depositNumber uint32) error { buf := bytes.NewBuffer(rawDeposits) scanner := bufio.NewScanner(buf) imt := new(IMT) @@ -497,12 +535,12 @@ func readDeposits(rawDeposits []byte) error { Str("root", common.Hash(imt.Roots[len(imt.Roots)-1]).String()). Msg("adding event to tree") // There's no point adding more leaves if we can prove the deposit already? - if evt.DepositCount >= *ulxlyInputArgs.DepositNum { + if evt.DepositCount >= depositNumber { break } } - p := imt.GetProof(*ulxlyInputArgs.DepositNum) + p := imt.GetProof(depositNumber) fmt.Println(p.String()) return nil } @@ -703,54 +741,52 @@ func generateEmptyHashes(height uint8) []common.Hash { return zeroHashes } -func generateTransactionPayload(ctx context.Context, client *ethclient.Client, ulxlyInputArgBridge string, ulxlyInputArgPvtKey string, ulxlyInputArgGasLimit uint64, ulxlyInputArgDestAddr string, ulxlyInputArgChainID string) (bridgeV2 *ulxly.Ulxly, privateKey *ecdsa.PrivateKey, fromAddress common.Address, gasLimit uint64, gasPrice *big.Int, toAddress common.Address, signer types.Signer) { - var err error +func generateTransactionPayload(ctx context.Context, client *ethclient.Client, ulxlyInputArgBridge string, ulxlyInputArgPvtKey string, ulxlyInputArgGasLimit uint64, ulxlyInputArgDestAddr string, ulxlyInputArgChainID string) (bridgeV2 *ulxly.Ulxly, toAddress common.Address, opts *bind.TransactOpts, err error) { bridgeV2, err = ulxly.NewUlxly(common.HexToAddress(ulxlyInputArgBridge), client) if err != nil { return } - privateKey, err = crypto.HexToECDSA(ulxlyInputArgPvtKey) + privateKey, err := crypto.HexToECDSA(ulxlyInputArgPvtKey) if err != nil { log.Error().Err(err).Msg("Unable to retrieve private key") } - publicKey := privateKey.Public() - publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) - if !ok { - log.Error().Msg("Error casting public key to ECDSA") - } - - fromAddress = crypto.PubkeyToAddress(*publicKeyECDSA) - // value := big.NewInt(*ulxlyInputArgs.Amount) - gasLimit = ulxlyInputArgGasLimit - gasPrice, err = client.SuggestGasPrice(ctx) - if err != nil { - log.Error().Err(err).Msg("Cannot get suggested gas price") - } + gasLimit := ulxlyInputArgGasLimit + // gasPrice, err := client.SuggestGasPrice(ctx) // This call is done automatically if it is not set + // if err != nil { + // log.Error().Err(err).Msg("Cannot get suggested gas price") + // } // gasTipCap, err := client.SuggestGasTipCap(ctx) // if err != nil { // log.Error().Err(err).Msg("Cannot get suggested gas tip cap") // } - toAddress = common.HexToAddress(ulxlyInputArgDestAddr) - chainID := new(big.Int) // For manual input of chainID, use the user's input if ulxlyInputArgChainID != "" { chainID.SetString(ulxlyInputArgChainID, 10) } else { // If there is no user input for chainID, infer it from context - chainID, err = client.NetworkID(ctx) + chainID, err = client.ChainID(ctx) if err != nil { log.Error().Err(err).Msg("Cannot get chain ID") return } } - signer = types.LatestSignerForChainID(chainID) - - return bridgeV2, privateKey, fromAddress, gasLimit, gasPrice, toAddress, signer + opts, err = bind.NewKeyedTransactorWithChainID(privateKey, chainID) + if err != nil { + log.Error().Err(err).Msg("Cannot generate transactionOpts") + return + } + opts.Context = ctx + opts.GasLimit = gasLimit + toAddress = common.HexToAddress(ulxlyInputArgDestAddr) + if toAddress == (common.Address{}) { + toAddress = opts.From + } + return bridgeV2, toAddress, opts, err } func getMerkleProofsExitRoots(bridgeServiceProofEndpoint string) (merkleProofArray [32][32]byte, rollupMerkleProofArray [32][32]byte, mainExitRoot []byte, rollupExitRoot []byte) { @@ -801,18 +837,18 @@ func getMerkleProofsExitRoots(bridgeServiceProofEndpoint string) (merkleProofArr return merkleProofArray, rollupMerkleProofArray, mainExitRoot, rollupExitRoot } -func getDeposits(bridgeServiceDepositsEndpoint string) (globalIndex *big.Int, originAddress common.Address, amount *big.Int, metadata []byte, err error) { - reqBridgeDeposits, err := http.Get(bridgeServiceDepositsEndpoint) +func getDeposit(bridgeServiceDepositsEndpoint string) (globalIndex *big.Int, originAddress common.Address, amount *big.Int, metadata []byte, leafType uint8, claimDestNetwork, claimOriginalNetwork uint32, err error) { + reqBridgeDeposit, err := http.Get(bridgeServiceDepositsEndpoint) if err != nil { log.Error().Err(err) return } - bodyBridgeDeposit, err := io.ReadAll(reqBridgeDeposits.Body) // Response body is []byte + bodyBridgeDeposit, err := io.ReadAll(reqBridgeDeposit.Body) // Response body is []byte if err != nil { log.Error().Err(err) return } - var bridgeDeposit BridgeDeposits + var bridgeDeposit BridgeDeposit err = json.Unmarshal(bodyBridgeDeposit, &bridgeDeposit) // Parse []byte to go struct pointer, and shadow err variable if err != nil { log.Error().Err(err).Msg("Can not unmarshal JSON") @@ -822,106 +858,335 @@ func getDeposits(bridgeServiceDepositsEndpoint string) (globalIndex *big.Int, or globalIndex = new(big.Int) amount = new(big.Int) - intClaimIndex, _ := strconv.Atoi(*ulxlyInputArgs.ClaimIndex) // Convert deposit_cnt to int - destinationNetwork, _ := strconv.Atoi(*ulxlyInputArgs.ClaimDestinationNetwork) - for index, deposit := range bridgeDeposit.Deposit { - intDepositCnt, _ := strconv.Atoi(deposit.DepositCnt) // Convert deposit_cnt to int - if intDepositCnt == intClaimIndex && destinationNetwork == deposit.DestNet { // deposit_cnt must match the user's input value - if !bridgeDeposit.Deposit[index].ReadyForClaim { - log.Error().Msg("The claim transaction is not yet ready to be claimed. Try again in a few blocks.") - return nil, common.HexToAddress("0x0"), nil, nil, errors.New("the claim transaction is not yet ready to be claimed, try again in a few blocks") - } else if bridgeDeposit.Deposit[index].ClaimTxHash != "" { - log.Info().Str("claimTxHash", bridgeDeposit.Deposit[index].ClaimTxHash).Msg("The claim transaction has already been claimed") - return nil, common.HexToAddress("0x0"), nil, nil, errors.New("the claim transaction has already been claimed") - } - originAddress = common.HexToAddress(bridgeDeposit.Deposit[index].OrigAddr) - globalIndex.SetString(bridgeDeposit.Deposit[index].GlobalIndex, 10) - amount.SetString(bridgeDeposit.Deposit[index].Amount, 10) - metadata = common.Hex2Bytes(bridgeDeposit.Deposit[index].Metadata) - return globalIndex, originAddress, amount, metadata, nil - } + defer reqBridgeDeposit.Body.Close() + if bridgeDeposit.Code != nil { + return globalIndex, originAddress, amount, metadata, leafType, claimDestNetwork, claimOriginalNetwork, fmt.Errorf("error code received getting the deposit. Code: %d, Message: %s", *bridgeDeposit.Code, *bridgeDeposit.Message) } - defer reqBridgeDeposits.Body.Close() - return nil, common.HexToAddress("0x0"), nil, nil, errors.New("failed to correctly get deposits") -} - -func checkGetDepositArgs(cmd *cobra.Command, args []string) error { - if *ulxlyInputArgs.BridgeAddress == "" { - return fmt.Errorf("please provide the bridge address") - } - if *ulxlyInputArgs.FromBlock > *ulxlyInputArgs.ToBlock { - return fmt.Errorf("the from block should be less than the to block") + if !bridgeDeposit.Deposit.ReadyForClaim { + log.Error().Msg("The claim transaction is not yet ready to be claimed. Try again in a few blocks.") + return nil, common.HexToAddress("0x0"), nil, nil, 0, 0, 0, errors.New("the claim transaction is not yet ready to be claimed, try again in a few blocks") + } else if bridgeDeposit.Deposit.ClaimTxHash != "" { + log.Info().Str("claimTxHash", bridgeDeposit.Deposit.ClaimTxHash).Msg("The claim transaction has already been claimed") + return nil, common.HexToAddress("0x0"), nil, nil, 0, 0, 0, errors.New("the claim transaction has already been claimed") } - return nil + originAddress = common.HexToAddress(bridgeDeposit.Deposit.OrigAddr) + globalIndex.SetString(bridgeDeposit.Deposit.GlobalIndex, 10) + amount.SetString(bridgeDeposit.Deposit.Amount, 10) + metadata = common.Hex2Bytes(bridgeDeposit.Deposit.Metadata) + leafType = bridgeDeposit.Deposit.LeafType + claimDestNetwork = bridgeDeposit.Deposit.DestNet + claimOriginalNetwork = bridgeDeposit.Deposit.OrigNet + return globalIndex, originAddress, amount, metadata, leafType, claimDestNetwork, claimOriginalNetwork, nil } -func checkDepositArgs(cmd *cobra.Command, args []string) error { - if *ulxlyInputArgs.DepositBridgeAddress == "" { - return fmt.Errorf("please provide the bridge address") - } - if *ulxlyInputArgs.DepositGasLimit < 130000 && *ulxlyInputArgs.DepositGasLimit != 0 { - return fmt.Errorf("the gas limit may be too low for the transaction to pass") - } - if *ulxlyInputArgs.DepositMessage && *ulxlyInputArgs.DepositWETH { - return fmt.Errorf("choose a single deposit mode (asset, message, or WETH)") - } - return nil -} +//go:embed BridgeAssetUsage.md +var bridgeAssetUsage string + +//go:embed BridgeMessageUsage.md +var bridgeMessageUsage string -func checkClaimArgs(cmd *cobra.Command, args []string) error { - if *ulxlyInputArgs.ClaimGasLimit < 150000 && *ulxlyInputArgs.ClaimGasLimit != 0 { - return fmt.Errorf("the gas limit may be too low for the transaction to pass") +//go:embed BridgeWETHMessageUsage.md +var bridgeWETHMessageUsage string + +//go:embed ClaimAssetUsage.md +var claimAssetUsage string + +//go:embed ClaimMessageUsage.md +var claimMessageUsage string + +//go:embed proofUsage.md +var proofUsage string + +//go:embed depositGetUsage.md +var depositGetUsage string + +func initCli(cmd *cobra.Command, args []string) { + app := cli.NewApp() + app.Name = "uLxLy" + app.Version = "v0.0.1" + app.Commands = []*cli.Command{ + { + Name: "ulxly", + Aliases: []string{}, + Usage: "options for ulxly", + Subcommands: []*cli.Command{ + { + Name: "bridge-asset", + Aliases: []string{}, + Usage: "Make a uLxLy bridge asset transaction", + Description: bridgeAssetUsage, + Action: bridgeAsset, + Flags: []cli.Flag{ + gasLimitFlag, + chainIDFlag, + privKeyFlag, + AmountFlag, + rpcURLFlag, + bridgeAddressFlag, + destNetworkFlag, + destAddressFlag, + tokenAddressFlag, + forceFlag, + callDataFlag, + timeoutFlag, + }, + }, + { + Name: "bridge-message", + Aliases: []string{}, + Usage: "Make a uLxLy bridge message transaction", + Description: bridgeMessageUsage, + Action: bridgeMessage, + Flags: []cli.Flag{ + gasLimitFlag, + chainIDFlag, + privKeyFlag, + AmountFlag, + rpcURLFlag, + bridgeAddressFlag, + destNetworkFlag, + destAddressFlag, + tokenAddressFlag, + forceFlag, + callDataFlag, + timeoutFlag, + }, + }, + { + Name: "bridge-message-weth", + Aliases: []string{}, + Usage: "Make a uLxLy bridge weth message transaction", + Description: bridgeWETHMessageUsage, + Action: bridgeWETHMessage, + Flags: []cli.Flag{ + gasLimitFlag, + chainIDFlag, + privKeyFlag, + AmountFlag, + rpcURLFlag, + bridgeAddressFlag, + destNetworkFlag, + destAddressFlag, + forceFlag, + callDataFlag, + timeoutFlag, + }, + }, + { + Name: "claim-asset", + Aliases: []string{}, + Usage: "Make a uLxLy claim asset transaction", + Description: claimAssetUsage, + Action: claimAsset, + Flags: []cli.Flag{ + depositCountFlag, + depositNetworkFlag, + bridgeServiceUrlFlag, + destAddressFlag, + rpcURLFlag, + privKeyFlag, + bridgeAddressFlag, + gasLimitFlag, + chainIDFlag, + timeoutFlag, + }, + }, + { + Name: "claim-message", + Aliases: []string{}, + Usage: "Make a uLxLy claim message transaction", + Description: claimMessageUsage, + Action: claimMessage, + Flags: []cli.Flag{ + depositCountFlag, + depositNetworkFlag, + bridgeServiceUrlFlag, + destAddressFlag, + rpcURLFlag, + privKeyFlag, + bridgeAddressFlag, + gasLimitFlag, + chainIDFlag, + timeoutFlag, + }, + }, + { + Name: "empty-proof", + Aliases: []string{}, + Usage: "Print an empty proof structure", + Description: "Use this command to print an empty proof response that's filled with zero-valued siblings like 0x0000000000000000000000000000000000000000000000000000000000000000. This can be useful when you need to submit a dummy proof.", + Action: emptyProof, + }, + { + Name: "zero-proof", + Aliases: []string{}, + Usage: "Print a proof structure with the zero hashes", + Description: `Use this command to print a proof response that's filled with the zero + hashes. This values are very helpful for debugging because it would + tell you how populated the tree is and roughly which leaves and + siblings are empty. It's also helpful for sanity checking a proof + response to understand if the hashed value is part of the zero hashes + or if it's actually an intermediate hash.`, + Action: zeroProof, + }, + { + Name: "proof", + Aliases: []string{}, + Usage: "Generate a merkle proof", + Description: proofUsage, + Action: proof, + Flags: []cli.Flag{depositNumberFlag}, + }, + { + Name: "deposit-get", + Aliases: []string{}, + Usage: "Get a range of deposits", + Description: depositGetUsage, + Action: readDeposit, + Flags: []cli.Flag{ + fromBlockFlag, + toBlockFlag, + filterFlag, + bridgeAddressFlag, + rpcURLFlag, + }, + }, + }, + }, } - if *ulxlyInputArgs.ClaimMessage && *ulxlyInputArgs.ClaimWETH { - return fmt.Errorf("choose a single claim mode (asset, message, or WETH)") + + err := app.Run(os.Args) + if err != nil { + fmt.Printf("\nError: %v\n", err) + os.Exit(1) } - return nil } -func init() { - ULxLyCmd.AddCommand(depositClaimCmd) - ULxLyCmd.AddCommand(depositNewCmd) - ULxLyCmd.AddCommand(depositGetCmd) - ULxLyCmd.AddCommand(ProofCmd) - ULxLyCmd.AddCommand(EmptyProofCmd) - ULxLyCmd.AddCommand(ZeroProofCmd) - - ulxlyInputArgs.ClaimIndex = depositClaimCmd.PersistentFlags().String("claim-index", "0", "The deposit count, or index to initiate a claim transaction for.") - ulxlyInputArgs.ClaimAddress = depositClaimCmd.PersistentFlags().String("claim-address", "", "The address that is receiving the bridged asset.") - ulxlyInputArgs.ClaimOriginNetwork = depositClaimCmd.PersistentFlags().String("origin-network", "0", "The network ID of the origin network.") - ulxlyInputArgs.ClaimDestinationNetwork = depositClaimCmd.PersistentFlags().String("destination-network", "1", "The network ID of the destination network.") - ulxlyInputArgs.ClaimRPCURL = depositClaimCmd.PersistentFlags().String("rpc-url", "http://127.0.0.1:8545", "The RPC endpoint of the destination network") - ulxlyInputArgs.BridgeServiceRPCURL = depositClaimCmd.PersistentFlags().String("bridge-service-url", "", "The RPC endpoint of the bridge service component.") - ulxlyInputArgs.ClaimPrivateKey = depositClaimCmd.PersistentFlags().String("private-key", "", "The private key of the sender account.") - ulxlyInputArgs.ClaimBridgeAddress = depositClaimCmd.PersistentFlags().String("bridge-address", "", "The address of the bridge contract.") - ulxlyInputArgs.ClaimGasLimit = depositClaimCmd.PersistentFlags().Uint64("gas-limit", 0, "The gas limit for the transaction. Setting this value to 0 will estimate the gas limit.") - ulxlyInputArgs.ClaimChainID = depositClaimCmd.PersistentFlags().String("chain-id", "", "The chainID.") - ulxlyInputArgs.ClaimTimeoutTxnReceipt = depositClaimCmd.PersistentFlags().Uint32("transaction-receipt-timeout", 60, "The timeout limit to check for the transaction receipt of the claim.") - ulxlyInputArgs.ClaimMessage = depositClaimCmd.PersistentFlags().Bool("claim-message", false, "Claim a message instead of an asset.") - ulxlyInputArgs.ClaimWETH = depositClaimCmd.PersistentFlags().Bool("claim-weth", false, "Claim a weth instead of an asset.") - - ulxlyInputArgs.DepositGasLimit = depositNewCmd.PersistentFlags().Uint64("gas-limit", 0, "The gas limit for the transaction. Setting this value to 0 will estimate the gas limit.") - ulxlyInputArgs.DepositChainID = depositNewCmd.PersistentFlags().String("chain-id", "", "The chainID.") - ulxlyInputArgs.DepositPrivateKey = depositNewCmd.PersistentFlags().String("private-key", "", "The private key of the sender account.") - ulxlyInputArgs.Amount = depositNewCmd.PersistentFlags().Int64("amount", 0, "The amount to send.") - ulxlyInputArgs.DepositRPCURL = depositNewCmd.PersistentFlags().String("rpc-url", "http://127.0.0.1:8545", "The RPC endpoint of the network") - ulxlyInputArgs.DepositBridgeAddress = depositNewCmd.PersistentFlags().String("bridge-address", "", "The address of the bridge contract.") - ulxlyInputArgs.DestinationNetwork = depositNewCmd.PersistentFlags().Uint32("destination-network", 1, "The destination network number.") - ulxlyInputArgs.DestinationAddress = depositNewCmd.PersistentFlags().String("destination-address", "", "The address of receiver in destination network.") - ulxlyInputArgs.TokenAddress = depositNewCmd.PersistentFlags().String("token-address", "0x0000000000000000000000000000000000000000", "The address of the token to send.") - ulxlyInputArgs.IsForced = depositNewCmd.PersistentFlags().Bool("force-update-root", true, "Force the update of the Global Exit Root.") - ulxlyInputArgs.CallData = depositNewCmd.PersistentFlags().String("call-data", "0x", "For bridging assets - raw data of the call `permit` of the token. For bridging messages - the metadata.") - ulxlyInputArgs.DepositTimeoutTxnReceipt = depositNewCmd.PersistentFlags().Uint32("transaction-receipt-timeout", 60, "The timeout limit to check for the transaction receipt of the deposit.") - ulxlyInputArgs.DepositMessage = depositNewCmd.PersistentFlags().Bool("bridge-message", false, "Bridge a message instead of an asset.") - ulxlyInputArgs.DepositWETH = depositNewCmd.PersistentFlags().Bool("bridge-weth", false, "Bridge a weth instead of an asset.") - - ulxlyInputArgs.FromBlock = depositGetCmd.PersistentFlags().Uint64("from-block", 0, "The block height to start query at.") - ulxlyInputArgs.ToBlock = depositGetCmd.PersistentFlags().Uint64("to-block", 0, "The block height to start query at.") - ulxlyInputArgs.RPCURL = depositGetCmd.PersistentFlags().String("rpc-url", "http://127.0.0.1:8545", "The RPC to query for events") - ulxlyInputArgs.FilterSize = depositGetCmd.PersistentFlags().Uint64("filter-size", 1000, "The batch size for individual filter queries") - - ulxlyInputArgs.BridgeAddress = depositGetCmd.Flags().String("bridge-address", "", "The address of the lxly bridge") - ulxlyInputArgs.InputFileName = ProofCmd.PersistentFlags().String("file-name", "", "The filename with ndjson data of deposits") - ulxlyInputArgs.DepositNum = ProofCmd.PersistentFlags().Uint32("deposit-number", 0, "The deposit that we would like to prove") +var gasLimitFlag = &cli.Uint64Flag{ + Name: "gas-limit", + Aliases: []string{"gl"}, + Usage: "This param is used to force the GasLimit", + Required: false, +} +var chainIDFlag = &cli.StringFlag{ + Name: "chain-id", + Aliases: []string{"id"}, + Usage: "This param is used to force the chainID", + Required: false, +} +var privKeyFlag = &cli.StringFlag{ + Name: "private-key", + Aliases: []string{"pk"}, + Usage: "This param is used to set the private key", + Required: true, +} +var AmountFlag = &cli.StringFlag{ + Name: "amount", + Aliases: []string{"a"}, + Usage: "This param is used to set the amount", + Required: true, +} +var rpcURLFlag = &cli.StringFlag{ + Name: "rpc-url", + Aliases: []string{"u"}, + Usage: "This param is used to set the rpc url", + Required: true, +} +var bridgeAddressFlag = &cli.StringFlag{ + Name: "bridge-address", + Aliases: []string{"b"}, + Usage: "This param is used to set the bridge address", + Required: true, +} +var destNetworkFlag = &cli.UintFlag{ + Name: "destination-network", + Aliases: []string{"dest-net"}, + Usage: "This param is used to set the destination network", + Required: true, +} +var destAddressFlag = &cli.StringFlag{ + Name: "destination-address", + Aliases: []string{"dest-addr"}, + Usage: "This param is used to set the destination address", + Required: false, +} +var tokenAddressFlag = &cli.StringFlag{ + Name: "token-address", + Aliases: []string{"token"}, + Usage: "This param is used to set the token address", + Required: false, +} +var forceFlag = &cli.BoolFlag{ + Name: "force-update-root", + Aliases: []string{"f"}, + Usage: "This param is used to force the ger update in the smc", + Required: false, + Value: true, +} +var callDataFlag = &cli.StringFlag{ + Name: "call-data", + Aliases: []string{"data"}, + Usage: "This param is used to set the callData", + Required: false, + Value: "0x", +} +var timeoutFlag = &cli.Uint64Flag{ + Name: "transaction-receipt-timeout", + Aliases: []string{"timeout"}, + Usage: "This param is used to change the timeout interval", + Value: 60, + Required: false, +} +var depositCountFlag = &cli.Uint64Flag{ + Name: "deposit-count", + Aliases: []string{"cnt"}, + Usage: "This param is used to specify the deposit counter", + Required: true, +} +var depositNetworkFlag = &cli.Uint64Flag{ + Name: "deposit-network", + Aliases: []string{"net"}, + Usage: "This param is used to specify the deposit network", + Required: true, +} +var bridgeServiceUrlFlag = &cli.StringFlag{ + Name: "bridge-service-url", + Aliases: []string{"bridge-url"}, + Usage: "This param is used to specify the bridge service url", + Required: true, +} +var inputFileNameFlag = &cli.StringFlag{ + Name: "file-name", + Aliases: []string{"file"}, + Usage: "The filename with ndjson data of deposits", + Required: true, +} +var fromBlockFlag = &cli.Uint64Flag{ + Name: "from-block", + Aliases: []string{"from"}, + Usage: "The block height to start query at.", + Value: 0, + Required: false, +} +var toBlockFlag = &cli.Uint64Flag{ + Name: "to-block", + Aliases: []string{"to"}, + Usage: "The block height to start query at.", + Value: 0, + Required: false, +} +var filterFlag = &cli.Uint64Flag{ + Name: "filter-size", + Aliases: []string{"filter"}, + Usage: "The batch size for individual filter queries.", + Value: 1000, + Required: false, +} +var depositNumberFlag = &cli.Uint64Flag{ + Name: "deposit-number", + Aliases: []string{"deposit"}, + Usage: "The deposit that we would like to prove", + Value: 0, + Required: false, } diff --git a/go.mod b/go.mod index 5357214a8..1cade649d 100644 --- a/go.mod +++ b/go.mod @@ -159,12 +159,16 @@ require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/urfave/cli/v2 v2.27.5 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect diff --git a/go.sum b/go.sum index 3124505bc..7e6180506 100644 --- a/go.sum +++ b/go.sum @@ -95,6 +95,8 @@ github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCe github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= @@ -404,6 +406,8 @@ github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2n github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -413,6 +417,8 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= From 3f9f59eccfc428fab3b834d2eb22cf88a4def46a Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Wed, 4 Dec 2024 18:09:43 -0500 Subject: [PATCH 02/24] refactor: switching to cobra.. needs testing --- cmd/ulxly/ulxly.go | 729 +++++++++++++++++++-------------------------- 1 file changed, 306 insertions(+), 423 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 7ea04e687..6ff71888f 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -27,7 +27,6 @@ import ( "github.com/0xPolygon/polygon-cli/bindings/ulxly" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - "github.com/urfave/cli/v2" ) const ( @@ -38,46 +37,6 @@ const ( TreeDepth = 32 ) -type uLxLyArgs struct { - FromBlock *uint64 - ToBlock *uint64 - RPCURL *string - BridgeAddress *string - FilterSize *uint64 - - ClaimIndex *string - ClaimAddress *string - ClaimOriginNetwork *string - ClaimDestinationNetwork *string - BridgeServiceRPCURL *string - ClaimRPCURL *string - ClaimPrivateKey *string - NetworkID *uint32 - ClaimBridgeAddress *string - ClaimGasLimit *uint64 - ClaimChainID *string - ClaimTimeoutTxnReceipt *uint32 - ClaimMessage *bool - ClaimWETH *bool - - InputFileName *string - DepositNum *uint32 - DepositPrivateKey *string - DepositGasLimit *uint64 - Amount *int64 // HACK: This should be big.Int but depositNewCmd.PersistentFlags() doesn't support that type. - DestinationNetwork *uint32 - DestinationAddress *string - DepositRPCURL *string - DepositBridgeAddress *string - DepositChainID *string - TokenAddress *string - IsForced *bool - CallData *string - DepositTimeoutTxnReceipt *uint32 - DepositMessage *bool - DepositWETH *bool -} - type IMT struct { Branches map[uint32][]common.Hash Leaves map[uint32]common.Hash @@ -123,22 +82,19 @@ type BridgeDeposit struct { Message *string `json:"message"` } -var ULxLyCmd = &cobra.Command{ - Use: "ulxly", - Short: "Utilities for interacting with the lxly bridge", - Long: "These are low level tools for directly scanning bridge events and constructing proofs.", - DisableFlagParsing: true, - Run: initCli, -} +func readDeposit(cmd *cobra.Command) error { + rpcUrl, err := cmd.Flags().GetString(ArgRPCURL) + if err != nil { + return err + } + + bridgeAddress := *inputUlxlyArgs.bridgeAddress + toBlock := *inputUlxlyArgs.toBlock + fromBlock := *inputUlxlyArgs.fromBlock + filter := *inputUlxlyArgs.filterSize -func readDeposit(ctx *cli.Context) error { - bridgeAddress := ctx.String(bridgeAddressFlag.Name) - rpcUrl := ctx.String(rpcURLFlag.Name) - toBlock := ctx.Uint64(toBlockFlag.Name) - fromBlock := ctx.Uint64(fromBlockFlag.Name) - filter := ctx.Uint64(filterFlag.Name) // Dial the Ethereum RPC server. - rpc, err := ethrpc.DialContext(ctx.Context, rpcUrl) + rpc, err := ethrpc.DialContext(cmd.Context(), rpcUrl) if err != nil { log.Error().Err(err).Msg("Unable to Dial RPC") return err @@ -160,7 +116,7 @@ func readDeposit(ctx *cli.Context) error { opts := bind.FilterOpts{ Start: currentBlock, End: &endBlock, - Context: ctx.Context, + Context: cmd.Context(), } evtV2Iterator, err := bridgeV2.FilterBridgeEvent(&opts) if err != nil { @@ -187,16 +143,16 @@ func readDeposit(ctx *cli.Context) error { return nil } -func proof(ctx *cli.Context) error { - depositNumber := ctx.Uint64(depositNumberFlag.Name) - rawDepositData, err := getInputData(ctx) +func proof(args []string) error { + depositNumber := *inputUlxlyArgs.depositNumber + rawDepositData, err := getInputData(args) if err != nil { return err } return readDeposits(rawDepositData, uint32(depositNumber)) } -func emptyProof(ctx *cli.Context) error { +func emptyProof() error { p := new(Proof) e := generateEmptyHashes(TreeDepth) @@ -205,7 +161,7 @@ func emptyProof(ctx *cli.Context) error { return nil } -func zeroProof(ctx *cli.Context) error { +func zeroProof() error { p := new(Proof) e := generateZeroHashes(TreeDepth) @@ -214,29 +170,29 @@ func zeroProof(ctx *cli.Context) error { return nil } -func bridgeAsset(ctx *cli.Context) error { - bridgeAddress := ctx.String(bridgeAddressFlag.Name) - privateKey := ctx.String(privKeyFlag.Name) - gasLimit := ctx.Uint64(gasLimitFlag.Name) - destinationAddress := ctx.String(destAddressFlag.Name) - chainID := ctx.String(chainIDFlag.Name) - amount := ctx.String(AmountFlag.Name) - tokenAddr := ctx.String(tokenAddressFlag.Name) - callDataString := ctx.String(callDataFlag.Name) - destinationNetwork := uint32(ctx.Uint(destNetworkFlag.Name)) - isForced := ctx.Bool(forceFlag.Name) - timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) - RPCURL := ctx.String(rpcURLFlag.Name) +func bridgeAsset(cmd *cobra.Command) error { + bridgeAddress := *inputUlxlyArgs.bridgeAddress + privateKey := *inputUlxlyArgs.privateKey + gasLimit := *inputUlxlyArgs.gasLimit + destinationAddress := *inputUlxlyArgs.destAddress + chainID := *inputUlxlyArgs.chainID + amount := *inputUlxlyArgs.value + tokenAddr := *inputUlxlyArgs.tokenAddress + callDataString := *inputUlxlyArgs.callData + destinationNetwork := *inputUlxlyArgs.destNetwork + isForced := *inputUlxlyArgs.forceUpdate + timeoutTxnReceipt := *inputUlxlyArgs.timeout + RPCURL := *inputUlxlyArgs.rpcURL // Dial the Ethereum RPC server. - client, err := ethclient.DialContext(ctx.Context, RPCURL) + client, err := ethclient.DialContext(cmd.Context(), RPCURL) if err != nil { log.Error().Err(err).Msg("Unable to Dial RPC") return err } defer client.Close() // Initialize and assign variables required to send transaction payload - bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + bridgeV2, toAddress, auth, err := generateTransactionPayload(cmd.Context(), client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) if err != nil { log.Error().Err(err).Msg("error generating transaction payload") return err @@ -256,32 +212,32 @@ func bridgeAsset(ctx *cli.Context) error { return err } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) - return WaitMineTransaction(ctx.Context, client, bridgeTxn, timeoutTxnReceipt) + return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) } -func bridgeMessage(ctx *cli.Context) error { - bridgeAddress := ctx.String(bridgeAddressFlag.Name) - privateKey := ctx.String(privKeyFlag.Name) - gasLimit := ctx.Uint64(gasLimitFlag.Name) - destinationAddress := ctx.String(destAddressFlag.Name) - chainID := ctx.String(chainIDFlag.Name) - amount := ctx.String(AmountFlag.Name) - tokenAddr := ctx.String(tokenAddressFlag.Name) - callDataString := ctx.String(callDataFlag.Name) - destinationNetwork := uint32(ctx.Uint(destNetworkFlag.Name)) - isForced := ctx.Bool(forceFlag.Name) - timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) - RPCURL := ctx.String(rpcURLFlag.Name) +func bridgeMessage(cmd *cobra.Command) error { + bridgeAddress := *inputUlxlyArgs.bridgeAddress + privateKey := *inputUlxlyArgs.privateKey + gasLimit := *inputUlxlyArgs.gasLimit + destinationAddress := *inputUlxlyArgs.destAddress + chainID := *inputUlxlyArgs.chainID + amount := *inputUlxlyArgs.value + tokenAddr := *inputUlxlyArgs.tokenAddress + callDataString := *inputUlxlyArgs.callData + destinationNetwork := *inputUlxlyArgs.destNetwork + isForced := *inputUlxlyArgs.forceUpdate + timeoutTxnReceipt := *inputUlxlyArgs.timeout + RPCURL := *inputUlxlyArgs.rpcURL // Dial the Ethereum RPC server. - client, err := ethclient.DialContext(ctx.Context, RPCURL) + client, err := ethclient.DialContext(cmd.Context(), RPCURL) if err != nil { log.Error().Err(err).Msg("Unable to Dial RPC") return err } defer client.Close() // Initialize and assign variables required to send transaction payload - bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + bridgeV2, toAddress, auth, err := generateTransactionPayload(cmd.Context(), client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) if err != nil { log.Error().Err(err).Msg("error generating transaction payload") return err @@ -301,30 +257,31 @@ func bridgeMessage(ctx *cli.Context) error { return err } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) - return WaitMineTransaction(ctx.Context, client, bridgeTxn, timeoutTxnReceipt) + return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) } -func bridgeWETHMessage(ctx *cli.Context) error { - bridgeAddress := ctx.String(bridgeAddressFlag.Name) - privateKey := ctx.String(privKeyFlag.Name) - gasLimit := ctx.Uint64(gasLimitFlag.Name) - destinationAddress := ctx.String(destAddressFlag.Name) - chainID := ctx.String(chainIDFlag.Name) - amount := ctx.String(AmountFlag.Name) - callDataString := ctx.String(callDataFlag.Name) - destinationNetwork := uint32(ctx.Uint(destNetworkFlag.Name)) - isForced := ctx.Bool(forceFlag.Name) - timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) - RPCURL := ctx.String(rpcURLFlag.Name) +func bridgeWETHMessage(cmd *cobra.Command) error { + bridgeAddress := *inputUlxlyArgs.bridgeAddress + privateKey := *inputUlxlyArgs.privateKey + gasLimit := *inputUlxlyArgs.gasLimit + destinationAddress := *inputUlxlyArgs.destAddress + chainID := *inputUlxlyArgs.chainID + amount := *inputUlxlyArgs.value + callDataString := *inputUlxlyArgs.callData + destinationNetwork := *inputUlxlyArgs.destNetwork + isForced := *inputUlxlyArgs.forceUpdate + timeoutTxnReceipt := *inputUlxlyArgs.timeout + RPCURL := *inputUlxlyArgs.rpcURL + // Dial the Ethereum RPC server. - client, err := ethclient.DialContext(ctx.Context, RPCURL) + client, err := ethclient.DialContext(cmd.Context(), RPCURL) if err != nil { log.Error().Err(err).Msg("Unable to Dial RPC") return err } defer client.Close() // Initialize and assign variables required to send transaction payload - bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + bridgeV2, toAddress, auth, err := generateTransactionPayload(cmd.Context(), client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) if err != nil { log.Error().Err(err).Msg("error generating transaction payload") return err @@ -348,30 +305,30 @@ func bridgeWETHMessage(ctx *cli.Context) error { return err } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) - return WaitMineTransaction(ctx.Context, client, bridgeTxn, timeoutTxnReceipt) + return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) } -func claimAsset(ctx *cli.Context) error { - bridgeAddress := ctx.String(bridgeAddressFlag.Name) - privateKey := ctx.String(privKeyFlag.Name) - gasLimit := ctx.Uint64(gasLimitFlag.Name) - destinationAddress := ctx.String(destAddressFlag.Name) - chainID := ctx.String(chainIDFlag.Name) - timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) - RPCURL := ctx.String(rpcURLFlag.Name) - depositCount := ctx.Uint64(depositCountFlag.Name) - depositNetwork := ctx.Uint64(depositNetworkFlag.Name) - bridgeServiceUrl := ctx.String(bridgeServiceUrlFlag.Name) +func claimAsset(cmd *cobra.Command) error { + bridgeAddress := *inputUlxlyArgs.bridgeAddress + privateKey := *inputUlxlyArgs.privateKey + gasLimit := *inputUlxlyArgs.gasLimit + destinationAddress := *inputUlxlyArgs.destAddress + chainID := *inputUlxlyArgs.chainID + timeoutTxnReceipt := *inputUlxlyArgs.timeout + RPCURL := *inputUlxlyArgs.rpcURL + depositCount := *inputUlxlyArgs.depositCount + depositNetwork := *inputUlxlyArgs.depositNetwork + bridgeServiceUrl := *inputUlxlyArgs.bridgeServiceURL // Dial Ethereum client - client, err := ethclient.DialContext(ctx.Context, RPCURL) + client, err := ethclient.DialContext(cmd.Context(), RPCURL) if err != nil { log.Error().Err(err).Msg("Unable to Dial RPC") return err } defer client.Close() // Initialize and assign variables required to send transaction payload - bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + bridgeV2, toAddress, auth, err := generateTransactionPayload(cmd.Context(), client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) if err != nil { log.Error().Err(err).Msg("error generating transaction payload") return err @@ -406,30 +363,30 @@ func claimAsset(ctx *cli.Context) error { return err } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) - return WaitMineTransaction(ctx.Context, client, claimTxn, timeoutTxnReceipt) + return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) } -func claimMessage(ctx *cli.Context) error { - bridgeAddress := ctx.String(bridgeAddressFlag.Name) - privateKey := ctx.String(privKeyFlag.Name) - gasLimit := ctx.Uint64(gasLimitFlag.Name) - destinationAddress := ctx.String(destAddressFlag.Name) - chainID := ctx.String(chainIDFlag.Name) - timeoutTxnReceipt := ctx.Uint64(timeoutFlag.Name) - RPCURL := ctx.String(rpcURLFlag.Name) - depositCount := ctx.Uint64(depositCountFlag.Name) - depositNetwork := ctx.Uint64(depositNetworkFlag.Name) - bridgeServiceUrl := ctx.String(bridgeServiceUrlFlag.Name) +func claimMessage(cmd *cobra.Command) error { + bridgeAddress := *inputUlxlyArgs.bridgeAddress + privateKey := *inputUlxlyArgs.privateKey + gasLimit := *inputUlxlyArgs.gasLimit + destinationAddress := *inputUlxlyArgs.destAddress + chainID := *inputUlxlyArgs.chainID + timeoutTxnReceipt := *inputUlxlyArgs.timeout + RPCURL := *inputUlxlyArgs.rpcURL + depositCount := *inputUlxlyArgs.depositCount + depositNetwork := *inputUlxlyArgs.depositNetwork + bridgeServiceUrl := *inputUlxlyArgs.bridgeServiceURL // Dial Ethereum client - client, err := ethclient.DialContext(ctx.Context, RPCURL) + client, err := ethclient.DialContext(cmd.Context(), RPCURL) if err != nil { log.Error().Err(err).Msg("Unable to Dial RPC") return err } defer client.Close() // Initialize and assign variables required to send transaction payload - bridgeV2, toAddress, auth, err := generateTransactionPayload(ctx.Context, client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + bridgeV2, toAddress, auth, err := generateTransactionPayload(cmd.Context(), client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) if err != nil { log.Error().Err(err).Msg("error generating transaction payload") return err @@ -456,7 +413,7 @@ func claimMessage(ctx *cli.Context) error { return err } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) - return WaitMineTransaction(ctx.Context, client, claimTxn, timeoutTxnReceipt) + return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) } // Wait for the transaction to be mined @@ -491,14 +448,14 @@ func WaitMineTransaction(ctx context.Context, client *ethclient.Client, tx *type } } -func getInputData(ctx *cli.Context) ([]byte, error) { - fileName := ctx.String(inputFileNameFlag.Name) +func getInputData(args []string) ([]byte, error) { + fileName := *inputUlxlyArgs.inputFileName if fileName != "" { return os.ReadFile(fileName) } - if ctx.Args().Len() > 1 { - concat := strings.Join(ctx.Args().Slice()[1:], " ") + if len(args) > 1 { + concat := strings.Join(args[1:], " ") return []byte(concat), nil } @@ -901,292 +858,218 @@ var proofUsage string //go:embed depositGetUsage.md var depositGetUsage string -func initCli(cmd *cobra.Command, args []string) { - app := cli.NewApp() - app.Name = "uLxLy" - app.Version = "v0.0.1" - app.Commands = []*cli.Command{ - { - Name: "ulxly", - Aliases: []string{}, - Usage: "options for ulxly", - Subcommands: []*cli.Command{ - { - Name: "bridge-asset", - Aliases: []string{}, - Usage: "Make a uLxLy bridge asset transaction", - Description: bridgeAssetUsage, - Action: bridgeAsset, - Flags: []cli.Flag{ - gasLimitFlag, - chainIDFlag, - privKeyFlag, - AmountFlag, - rpcURLFlag, - bridgeAddressFlag, - destNetworkFlag, - destAddressFlag, - tokenAddressFlag, - forceFlag, - callDataFlag, - timeoutFlag, - }, - }, - { - Name: "bridge-message", - Aliases: []string{}, - Usage: "Make a uLxLy bridge message transaction", - Description: bridgeMessageUsage, - Action: bridgeMessage, - Flags: []cli.Flag{ - gasLimitFlag, - chainIDFlag, - privKeyFlag, - AmountFlag, - rpcURLFlag, - bridgeAddressFlag, - destNetworkFlag, - destAddressFlag, - tokenAddressFlag, - forceFlag, - callDataFlag, - timeoutFlag, - }, - }, - { - Name: "bridge-message-weth", - Aliases: []string{}, - Usage: "Make a uLxLy bridge weth message transaction", - Description: bridgeWETHMessageUsage, - Action: bridgeWETHMessage, - Flags: []cli.Flag{ - gasLimitFlag, - chainIDFlag, - privKeyFlag, - AmountFlag, - rpcURLFlag, - bridgeAddressFlag, - destNetworkFlag, - destAddressFlag, - forceFlag, - callDataFlag, - timeoutFlag, - }, - }, - { - Name: "claim-asset", - Aliases: []string{}, - Usage: "Make a uLxLy claim asset transaction", - Description: claimAssetUsage, - Action: claimAsset, - Flags: []cli.Flag{ - depositCountFlag, - depositNetworkFlag, - bridgeServiceUrlFlag, - destAddressFlag, - rpcURLFlag, - privKeyFlag, - bridgeAddressFlag, - gasLimitFlag, - chainIDFlag, - timeoutFlag, - }, - }, - { - Name: "claim-message", - Aliases: []string{}, - Usage: "Make a uLxLy claim message transaction", - Description: claimMessageUsage, - Action: claimMessage, - Flags: []cli.Flag{ - depositCountFlag, - depositNetworkFlag, - bridgeServiceUrlFlag, - destAddressFlag, - rpcURLFlag, - privKeyFlag, - bridgeAddressFlag, - gasLimitFlag, - chainIDFlag, - timeoutFlag, - }, - }, - { - Name: "empty-proof", - Aliases: []string{}, - Usage: "Print an empty proof structure", - Description: "Use this command to print an empty proof response that's filled with zero-valued siblings like 0x0000000000000000000000000000000000000000000000000000000000000000. This can be useful when you need to submit a dummy proof.", - Action: emptyProof, - }, - { - Name: "zero-proof", - Aliases: []string{}, - Usage: "Print a proof structure with the zero hashes", - Description: `Use this command to print a proof response that's filled with the zero - hashes. This values are very helpful for debugging because it would - tell you how populated the tree is and roughly which leaves and - siblings are empty. It's also helpful for sanity checking a proof - response to understand if the hashed value is part of the zero hashes - or if it's actually an intermediate hash.`, - Action: zeroProof, - }, - { - Name: "proof", - Aliases: []string{}, - Usage: "Generate a merkle proof", - Description: proofUsage, - Action: proof, - Flags: []cli.Flag{depositNumberFlag}, - }, - { - Name: "deposit-get", - Aliases: []string{}, - Usage: "Get a range of deposits", - Description: depositGetUsage, - Action: readDeposit, - Flags: []cli.Flag{ - fromBlockFlag, - toBlockFlag, - filterFlag, - bridgeAddressFlag, - rpcURLFlag, - }, - }, - }, - }, - } - - err := app.Run(os.Args) - if err != nil { - fmt.Printf("\nError: %v\n", err) - os.Exit(1) - } -} - -var gasLimitFlag = &cli.Uint64Flag{ - Name: "gas-limit", - Aliases: []string{"gl"}, - Usage: "This param is used to force the GasLimit", - Required: false, -} -var chainIDFlag = &cli.StringFlag{ - Name: "chain-id", - Aliases: []string{"id"}, - Usage: "This param is used to force the chainID", - Required: false, -} -var privKeyFlag = &cli.StringFlag{ - Name: "private-key", - Aliases: []string{"pk"}, - Usage: "This param is used to set the private key", - Required: true, -} -var AmountFlag = &cli.StringFlag{ - Name: "amount", - Aliases: []string{"a"}, - Usage: "This param is used to set the amount", - Required: true, -} -var rpcURLFlag = &cli.StringFlag{ - Name: "rpc-url", - Aliases: []string{"u"}, - Usage: "This param is used to set the rpc url", - Required: true, -} -var bridgeAddressFlag = &cli.StringFlag{ - Name: "bridge-address", - Aliases: []string{"b"}, - Usage: "This param is used to set the bridge address", - Required: true, -} -var destNetworkFlag = &cli.UintFlag{ - Name: "destination-network", - Aliases: []string{"dest-net"}, - Usage: "This param is used to set the destination network", - Required: true, -} -var destAddressFlag = &cli.StringFlag{ - Name: "destination-address", - Aliases: []string{"dest-addr"}, - Usage: "This param is used to set the destination address", - Required: false, -} -var tokenAddressFlag = &cli.StringFlag{ - Name: "token-address", - Aliases: []string{"token"}, - Usage: "This param is used to set the token address", - Required: false, -} -var forceFlag = &cli.BoolFlag{ - Name: "force-update-root", - Aliases: []string{"f"}, - Usage: "This param is used to force the ger update in the smc", - Required: false, - Value: true, -} -var callDataFlag = &cli.StringFlag{ - Name: "call-data", - Aliases: []string{"data"}, - Usage: "This param is used to set the callData", - Required: false, - Value: "0x", -} -var timeoutFlag = &cli.Uint64Flag{ - Name: "transaction-receipt-timeout", - Aliases: []string{"timeout"}, - Usage: "This param is used to change the timeout interval", - Value: 60, - Required: false, -} -var depositCountFlag = &cli.Uint64Flag{ - Name: "deposit-count", - Aliases: []string{"cnt"}, - Usage: "This param is used to specify the deposit counter", - Required: true, -} -var depositNetworkFlag = &cli.Uint64Flag{ - Name: "deposit-network", - Aliases: []string{"net"}, - Usage: "This param is used to specify the deposit network", - Required: true, -} -var bridgeServiceUrlFlag = &cli.StringFlag{ - Name: "bridge-service-url", - Aliases: []string{"bridge-url"}, - Usage: "This param is used to specify the bridge service url", - Required: true, +var ULxLyCmd = &cobra.Command{ + Use: "ulxly", + Short: "Utilities for interacting with the lxly bridge", + Long: "These are low level tools for directly scanning bridge events and constructing proofs.", + Args: cobra.NoArgs, } -var inputFileNameFlag = &cli.StringFlag{ - Name: "file-name", - Aliases: []string{"file"}, - Usage: "The filename with ndjson data of deposits", - Required: true, +var ulxlyBridgeAndClaimCmd = &cobra.Command{ + Args: cobra.NoArgs, + Hidden: true, } -var fromBlockFlag = &cli.Uint64Flag{ - Name: "from-block", - Aliases: []string{"from"}, - Usage: "The block height to start query at.", - Value: 0, - Required: false, + +var ulxlxBridgeCmd = &cobra.Command{ + Use: "bridge", + Short: "commands for making deposits to the uLxLy bridge", + Args: cobra.NoArgs, } -var toBlockFlag = &cli.Uint64Flag{ - Name: "to-block", - Aliases: []string{"to"}, - Usage: "The block height to start query at.", - Value: 0, - Required: false, + +var ulxlyClaimCmd = &cobra.Command{ + Use: "claim", + Short: "commands for making claims of deposits from the uLxLy bridge", + Args: cobra.NoArgs, } -var filterFlag = &cli.Uint64Flag{ - Name: "filter-size", - Aliases: []string{"filter"}, - Usage: "The batch size for individual filter queries.", - Value: 1000, - Required: false, + +type ulxlyArgs struct { + gasLimit *uint64 + chainID *string + privateKey *string + value *string + rpcURL *string + bridgeAddress *string + destNetwork *uint32 + destAddress *string + tokenAddress *string + forceUpdate *bool + callData *string + timeout *uint64 + depositCount *uint64 + depositNetwork *uint64 + bridgeServiceURL *string + inputFileName *string + fromBlock *uint64 + toBlock *uint64 + filterSize *uint64 + depositNumber *uint64 } -var depositNumberFlag = &cli.Uint64Flag{ - Name: "deposit-number", - Aliases: []string{"deposit"}, - Usage: "The deposit that we would like to prove", - Value: 0, - Required: false, + +var inputUlxlyArgs = ulxlyArgs{} + +var ( + bridgeAssetCommand *cobra.Command + bridgeMessageCommand *cobra.Command + bridgeMessageWETHCommand *cobra.Command + claimAssetCommand *cobra.Command + claimMessageCommand *cobra.Command + emptyProofCommand *cobra.Command + zeroProofCommand *cobra.Command + proofCommand *cobra.Command + getDepositCommand *cobra.Command +) + +const ( + ArgGasLimit = "gas-limit" + ArgChainID = "chain-id" + ArgPrivateKey = "private-key" + ArgValue = "value" + ArgRPCURL = "rpc-url" + ArgBridgeAddress = "bridge-address" + ArgDestNetwork = "destination-network" + ArgDestAddress = "destination-address" + ArgForceUpdate = "force-update-root" + ArgCallData = "call-data" + ArgTimeout = "transaction-receipt-timeout" + ArgDepositCount = "deposit-count" + ArgDepositNetwork = "deposit-network" + ArgBridgeServiceURL = "bridge-service-url" + ArgFileName = "file-name" + ArgFromBlock = "from-block" + ArgToBlock = "to-block" + ArgFilterSize = "filter-size" +) + +func init() { + bridgeAssetCommand = &cobra.Command{ + Use: "asset", + Short: "send a single deposit of value or an ERC20 into the bridge", + RunE: func(cmd *cobra.Command, args []string) error { + return bridgeAsset(cmd) + }, + } + bridgeMessageCommand = &cobra.Command{ + Use: "message", + Short: "send some value along with call data into the bridge", + RunE: func(cmd *cobra.Command, args []string) error { + return bridgeMessage(cmd) + }, + } + bridgeMessageWETHCommand = &cobra.Command{ + Use: "weth", + Short: "send some WETH into the bridge", + RunE: func(cmd *cobra.Command, args []string) error { + return bridgeWETHMessage(cmd) + }, + } + claimAssetCommand = &cobra.Command{ + Use: "asset", + Short: "perform a claim of a given deposit in the bridge", + RunE: func(cmd *cobra.Command, args []string) error { + return claimAsset(cmd) + }, + } + claimMessageCommand = &cobra.Command{ + Use: "message", + Short: "perform a claim of a given message in the birdge", + RunE: func(cmd *cobra.Command, args []string) error { + return nil + }, + } + emptyProofCommand = &cobra.Command{ + Use: "empty-proof", + Short: "create an empty proof", + Long: "Use this command to print an empty proof response that's filled with zero-valued siblings like 0x0000000000000000000000000000000000000000000000000000000000000000. This can be useful when you need to submit a dummy proof.", + RunE: func(cmd *cobra.Command, args []string) error { + return emptyProof() + }, + } + zeroProofCommand = &cobra.Command{ + Use: "zero-proof", + Short: "create a proof that's filled with zeros", + Long: `Use this command to print a proof response that's filled with the zero + hashes. This values are very helpful for debugging because it would + tell you how populated the tree is and roughly which leaves and + siblings are empty. It's also helpful for sanity checking a proof + response to understand if the hashed value is part of the zero hashes + or if it's actually an intermediate hash.`, + RunE: func(cmd *cobra.Command, args []string) error { + return zeroProof() + }, + } + proofCommand = &cobra.Command{ + Use: "proof", + Short: "generate a proof for a given range of deposits", + RunE: func(cmd *cobra.Command, args []string) error { + return proof(args) + }, + } + getDepositCommand = &cobra.Command{ + Use: "get-deposits", + Short: "generate ndjson for each bridge deposit over a particular range of blocks", + RunE: func(cmd *cobra.Command, args []string) error { + return readDeposit(cmd) + }, + } + + // Arguments for both bridge and claim + inputUlxlyArgs.gasLimit = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgGasLimit, 0, "force a gas limit when sending a transaction") + inputUlxlyArgs.chainID = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgChainID, "", "set the chain id to be used in the transaction") + inputUlxlyArgs.privateKey = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgPrivateKey, "", "the hex encoded private key to be used when sending the tx") + inputUlxlyArgs.rpcURL = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgRPCURL, "", "the URL of the RPC to send the transaction") + inputUlxlyArgs.bridgeAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgBridgeAddress, "", "the address of the lxly bridge") + inputUlxlyArgs.destAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgDestAddress, "", "the address where the bridge will be sent to") + inputUlxlyArgs.callData = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") + inputUlxlyArgs.timeout = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgTimeout, 60, "the amount of time to wait while trying to confirm a transaction receipt") + ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgPrivateKey) + ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgRPCURL) + ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgBridgeAddress) + ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgDestAddress) + + // bridge specific args + inputUlxlyArgs.forceUpdate = ulxlxBridgeCmd.PersistentFlags().Bool(ArgForceUpdate, true, "indicates if the new global exit root is updated or not") + inputUlxlyArgs.value = ulxlxBridgeCmd.PersistentFlags().String(ArgValue, "", "the amount in wei to be sent along with the transaction") + inputUlxlyArgs.destNetwork = ulxlxBridgeCmd.PersistentFlags().Uint32(ArgDestNetwork, 0, "the rollup id of the destination network") + ulxlxBridgeCmd.MarkFlagRequired(ArgDestNetwork) + + // Claim specific args + inputUlxlyArgs.depositCount = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositCount, 0, "the deposit count of the bridge transaction") + inputUlxlyArgs.depositNetwork = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositNetwork, 0, "the rollup id of the network where the bridge is being claimed") + inputUlxlyArgs.bridgeServiceURL = ulxlyClaimCmd.PersistentFlags().String(ArgBridgeServiceURL, "", "the URL of the bridge service") + ulxlyClaimCmd.MarkFlagRequired(ArgDepositCount) + ulxlyClaimCmd.MarkFlagRequired(ArgDepositNetwork) + ulxlyClaimCmd.MarkFlagRequired(ArgBridgeServiceURL) + + // Args that are just for the get deposit command + inputUlxlyArgs.inputFileName = getDepositCommand.Flags().String(ArgFileName, "", "An ndjson file with deposit data") + inputUlxlyArgs.fromBlock = getDepositCommand.Flags().Uint64(ArgFromBlock, 0, "The start of the range of blocks to retrieve") + inputUlxlyArgs.toBlock = getDepositCommand.Flags().Uint64(ArgToBlock, 0, "The end of the range of blocks to retrieve") + inputUlxlyArgs.filterSize = getDepositCommand.Flags().Uint64(ArgFilterSize, 1000, "The batch size for individual filter queries") + getDepositCommand.Flags().String(ArgRPCURL, "", "The RPC URL to read deposit data") + getDepositCommand.MarkFlagRequired(ArgFromBlock) + getDepositCommand.MarkFlagRequired(ArgToBlock) + getDepositCommand.MarkFlagRequired(ArgRPCURL) + + // Top Level + ULxLyCmd.AddCommand(ulxlyBridgeAndClaimCmd) + ULxLyCmd.AddCommand(emptyProofCommand) + ULxLyCmd.AddCommand(zeroProofCommand) + ULxLyCmd.AddCommand(proofCommand) + ULxLyCmd.AddCommand(getDepositCommand) + + ULxLyCmd.AddCommand(ulxlxBridgeCmd) + ULxLyCmd.AddCommand(ulxlyClaimCmd) + + // Bridge and Claim + ulxlyBridgeAndClaimCmd.AddCommand(ulxlxBridgeCmd) + ulxlyBridgeAndClaimCmd.AddCommand(ulxlyClaimCmd) + + // Bridge + ulxlxBridgeCmd.AddCommand(bridgeAssetCommand) + ulxlxBridgeCmd.AddCommand(bridgeMessageCommand) + ulxlxBridgeCmd.AddCommand(bridgeMessageWETHCommand) + + // Claim + ulxlyClaimCmd.AddCommand(claimAssetCommand) + ulxlyClaimCmd.AddCommand(claimMessageCommand) + } From f0e026df63f889cc2dcdd694e5a9ace829437a4c Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Wed, 4 Dec 2024 19:18:51 -0500 Subject: [PATCH 03/24] fix: minor issues related to missing field and 0x prefix --- cmd/ulxly/ulxly.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 6ff71888f..8d4e323fe 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -699,6 +699,7 @@ func generateEmptyHashes(height uint8) []common.Hash { } func generateTransactionPayload(ctx context.Context, client *ethclient.Client, ulxlyInputArgBridge string, ulxlyInputArgPvtKey string, ulxlyInputArgGasLimit uint64, ulxlyInputArgDestAddr string, ulxlyInputArgChainID string) (bridgeV2 *ulxly.Ulxly, toAddress common.Address, opts *bind.TransactOpts, err error) { + ulxlyInputArgPvtKey = strings.TrimPrefix(ulxlyInputArgPvtKey, "0x") bridgeV2, err = ulxly.NewUlxly(common.HexToAddress(ulxlyInputArgBridge), client) if err != nil { return @@ -937,6 +938,7 @@ const ( ArgFromBlock = "from-block" ArgToBlock = "to-block" ArgFilterSize = "filter-size" + ArgTokenAddress = "token-address" ) func init() { @@ -1029,6 +1031,7 @@ func init() { inputUlxlyArgs.forceUpdate = ulxlxBridgeCmd.PersistentFlags().Bool(ArgForceUpdate, true, "indicates if the new global exit root is updated or not") inputUlxlyArgs.value = ulxlxBridgeCmd.PersistentFlags().String(ArgValue, "", "the amount in wei to be sent along with the transaction") inputUlxlyArgs.destNetwork = ulxlxBridgeCmd.PersistentFlags().Uint32(ArgDestNetwork, 0, "the rollup id of the destination network") + inputUlxlyArgs.tokenAddress = ulxlxBridgeCmd.PersistentFlags().String(ArgTokenAddress, "0x0000000000000000000000000000000000000000", "the address of an ERC20 token to be used") ulxlxBridgeCmd.MarkFlagRequired(ArgDestNetwork) // Claim specific args @@ -1048,7 +1051,7 @@ func init() { getDepositCommand.MarkFlagRequired(ArgFromBlock) getDepositCommand.MarkFlagRequired(ArgToBlock) getDepositCommand.MarkFlagRequired(ArgRPCURL) - + // Top Level ULxLyCmd.AddCommand(ulxlyBridgeAndClaimCmd) ULxLyCmd.AddCommand(emptyProofCommand) From 0bf4f494c67e7fed3597fe1e3d3588765c28f790 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Wed, 4 Dec 2024 20:15:19 -0500 Subject: [PATCH 04/24] fix: deposit_cnt type, missing function call, call data in wrong level --- cmd/ulxly/ulxly.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 8d4e323fe..e01dea942 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -70,7 +70,7 @@ type BridgeDeposit struct { DestNet uint32 `json:"dest_net"` DestAddr string `json:"dest_addr"` BlockNum string `json:"block_num"` - DepositCnt uint32 `json:"deposit_cnt"` + DepositCnt uint32 `json:"deposit_cnt,string"` NetworkID uint32 `json:"network_id"` TxHash string `json:"tx_hash"` ClaimTxHash string `json:"claim_tx_hash"` @@ -974,7 +974,7 @@ func init() { Use: "message", Short: "perform a claim of a given message in the birdge", RunE: func(cmd *cobra.Command, args []string) error { - return nil + return claimMessage(cmd) }, } emptyProofCommand = &cobra.Command{ @@ -1020,7 +1020,6 @@ func init() { inputUlxlyArgs.rpcURL = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgRPCURL, "", "the URL of the RPC to send the transaction") inputUlxlyArgs.bridgeAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgBridgeAddress, "", "the address of the lxly bridge") inputUlxlyArgs.destAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgDestAddress, "", "the address where the bridge will be sent to") - inputUlxlyArgs.callData = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") inputUlxlyArgs.timeout = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgTimeout, 60, "the amount of time to wait while trying to confirm a transaction receipt") ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgPrivateKey) ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgRPCURL) @@ -1032,6 +1031,7 @@ func init() { inputUlxlyArgs.value = ulxlxBridgeCmd.PersistentFlags().String(ArgValue, "", "the amount in wei to be sent along with the transaction") inputUlxlyArgs.destNetwork = ulxlxBridgeCmd.PersistentFlags().Uint32(ArgDestNetwork, 0, "the rollup id of the destination network") inputUlxlyArgs.tokenAddress = ulxlxBridgeCmd.PersistentFlags().String(ArgTokenAddress, "0x0000000000000000000000000000000000000000", "the address of an ERC20 token to be used") + inputUlxlyArgs.callData = ulxlxBridgeCmd.PersistentFlags().String(ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") ulxlxBridgeCmd.MarkFlagRequired(ArgDestNetwork) // Claim specific args From 9a6b9eb6ac6743238f4d286ae2de2a6b1aa3252b Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Wed, 4 Dec 2024 23:15:30 -0500 Subject: [PATCH 05/24] feat: adding ability to override global index while the bug is fixed --- cmd/ulxly/ulxly.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index e01dea942..5087774bd 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -319,6 +319,7 @@ func claimAsset(cmd *cobra.Command) error { depositCount := *inputUlxlyArgs.depositCount depositNetwork := *inputUlxlyArgs.depositNetwork bridgeServiceUrl := *inputUlxlyArgs.bridgeServiceURL + globalIndexOverride := *inputUlxlyArgs.globalIndex // Dial Ethereum client client, err := ethclient.DialContext(cmd.Context(), RPCURL) @@ -356,7 +357,9 @@ func claimAsset(cmd *cobra.Command) error { if leafType != 0 { log.Warn().Msg("Deposit leafType is not asset") } - + if globalIndexOverride != "" { + globalIndex.SetString(globalIndexOverride, 10) + } claimTxn, err := bridgeV2.ClaimAsset(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) if err != nil { log.Error().Err(err).Msg("Unable to interact with bridge contract") @@ -377,6 +380,7 @@ func claimMessage(cmd *cobra.Command) error { depositCount := *inputUlxlyArgs.depositCount depositNetwork := *inputUlxlyArgs.depositNetwork bridgeServiceUrl := *inputUlxlyArgs.bridgeServiceURL + globalIndexOverride := *inputUlxlyArgs.globalIndex // Dial Ethereum client client, err := ethclient.DialContext(cmd.Context(), RPCURL) @@ -406,7 +410,10 @@ func claimMessage(cmd *cobra.Command) error { if leafType != 1 { log.Warn().Msg("Deposit leafType is not message") } - + if globalIndexOverride != "" { + globalIndex.SetString(globalIndexOverride, 10) + } + //ClaimMessage(opts *bind.TransactOpts, smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { claimTxn, err := bridgeV2.ClaimMessage(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) if err != nil { log.Error().Err(err).Msg("Unable to interact with bridge contract") @@ -903,6 +910,7 @@ type ulxlyArgs struct { toBlock *uint64 filterSize *uint64 depositNumber *uint64 + globalIndex *string } var inputUlxlyArgs = ulxlyArgs{} @@ -939,6 +947,7 @@ const ( ArgToBlock = "to-block" ArgFilterSize = "filter-size" ArgTokenAddress = "token-address" + ArgGlobalIndex = "global-index" ) func init() { @@ -1038,6 +1047,8 @@ func init() { inputUlxlyArgs.depositCount = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositCount, 0, "the deposit count of the bridge transaction") inputUlxlyArgs.depositNetwork = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositNetwork, 0, "the rollup id of the network where the bridge is being claimed") inputUlxlyArgs.bridgeServiceURL = ulxlyClaimCmd.PersistentFlags().String(ArgBridgeServiceURL, "", "the URL of the bridge service") + inputUlxlyArgs.globalIndex = ulxlyClaimCmd.PersistentFlags().String(ArgGlobalIndex, "", "an override of the global index value") + ulxlyClaimCmd.MarkFlagRequired(ArgDepositCount) ulxlyClaimCmd.MarkFlagRequired(ArgDepositNetwork) ulxlyClaimCmd.MarkFlagRequired(ArgBridgeServiceURL) From a99392198acacbcbfa05db2b9c5a36ccd2902a44 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Thu, 5 Dec 2024 09:29:57 -0500 Subject: [PATCH 06/24] fix: dropping string tag --- cmd/ulxly/ulxly.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 5087774bd..b4a141a39 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -70,7 +70,7 @@ type BridgeDeposit struct { DestNet uint32 `json:"dest_net"` DestAddr string `json:"dest_addr"` BlockNum string `json:"block_num"` - DepositCnt uint32 `json:"deposit_cnt,string"` + DepositCnt uint32 `json:"deposit_cnt"` NetworkID uint32 `json:"network_id"` TxHash string `json:"tx_hash"` ClaimTxHash string `json:"claim_tx_hash"` From 50349162e14335636a8109cceaad635c84dc4844 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Thu, 5 Dec 2024 19:18:46 -0500 Subject: [PATCH 07/24] feat: adding dry-run and gas-price --- cmd/ulxly/ulxly.go | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index b4a141a39..14dbd69e0 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -425,6 +425,10 @@ func claimMessage(cmd *cobra.Command) error { // Wait for the transaction to be mined func WaitMineTransaction(ctx context.Context, client *ethclient.Client, tx *types.Transaction, txTimeout uint64) error { + if inputUlxlyArgs.dryRun != nil && *inputUlxlyArgs.dryRun { + log.Info().Msg("Skipping receipt check. Dry run is enabled") + return nil + } txnMinedTimer := time.NewTimer(time.Duration(txTimeout) * time.Second) defer txnMinedTimer.Stop() for { @@ -745,6 +749,14 @@ func generateTransactionPayload(ctx context.Context, client *ethclient.Client, u log.Error().Err(err).Msg("Cannot generate transactionOpts") return } + if inputUlxlyArgs.gasPrice != nil && *inputUlxlyArgs.gasPrice != "" { + gasPrice := new(big.Int) + gasPrice.SetString(*inputUlxlyArgs.gasPrice, 10) + opts.GasPrice = gasPrice + } + if inputUlxlyArgs.dryRun != nil && *inputUlxlyArgs.dryRun { + opts.NoSend = true + } opts.Context = ctx opts.GasLimit = gasLimit toAddress = common.HexToAddress(ulxlyInputArgDestAddr) @@ -911,6 +923,8 @@ type ulxlyArgs struct { filterSize *uint64 depositNumber *uint64 globalIndex *string + gasPrice *string + dryRun *bool } var inputUlxlyArgs = ulxlyArgs{} @@ -948,6 +962,8 @@ const ( ArgFilterSize = "filter-size" ArgTokenAddress = "token-address" ArgGlobalIndex = "global-index" + ArgDryRun = "dry-run" + ArgGasPrice = "gas-price" ) func init() { @@ -1030,10 +1046,12 @@ func init() { inputUlxlyArgs.bridgeAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgBridgeAddress, "", "the address of the lxly bridge") inputUlxlyArgs.destAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgDestAddress, "", "the address where the bridge will be sent to") inputUlxlyArgs.timeout = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgTimeout, 60, "the amount of time to wait while trying to confirm a transaction receipt") - ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgPrivateKey) - ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgRPCURL) - ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgBridgeAddress) - ulxlyBridgeAndClaimCmd.MarkFlagRequired(ArgDestAddress) + inputUlxlyArgs.gasPrice = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgGasPrice, "", "the gas price to be used") + inputUlxlyArgs.dryRun = ulxlyBridgeAndClaimCmd.PersistentFlags().Bool(ArgDryRun, false, "do all of the transaction steps but do not send the transaction") + ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey) + ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL) + ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress) + ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgDestAddress) // bridge specific args inputUlxlyArgs.forceUpdate = ulxlxBridgeCmd.PersistentFlags().Bool(ArgForceUpdate, true, "indicates if the new global exit root is updated or not") @@ -1041,7 +1059,7 @@ func init() { inputUlxlyArgs.destNetwork = ulxlxBridgeCmd.PersistentFlags().Uint32(ArgDestNetwork, 0, "the rollup id of the destination network") inputUlxlyArgs.tokenAddress = ulxlxBridgeCmd.PersistentFlags().String(ArgTokenAddress, "0x0000000000000000000000000000000000000000", "the address of an ERC20 token to be used") inputUlxlyArgs.callData = ulxlxBridgeCmd.PersistentFlags().String(ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") - ulxlxBridgeCmd.MarkFlagRequired(ArgDestNetwork) + ulxlxBridgeCmd.MarkPersistentFlagRequired(ArgDestNetwork) // Claim specific args inputUlxlyArgs.depositCount = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositCount, 0, "the deposit count of the bridge transaction") @@ -1049,9 +1067,9 @@ func init() { inputUlxlyArgs.bridgeServiceURL = ulxlyClaimCmd.PersistentFlags().String(ArgBridgeServiceURL, "", "the URL of the bridge service") inputUlxlyArgs.globalIndex = ulxlyClaimCmd.PersistentFlags().String(ArgGlobalIndex, "", "an override of the global index value") - ulxlyClaimCmd.MarkFlagRequired(ArgDepositCount) - ulxlyClaimCmd.MarkFlagRequired(ArgDepositNetwork) - ulxlyClaimCmd.MarkFlagRequired(ArgBridgeServiceURL) + ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount) + ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork) + ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL) // Args that are just for the get deposit command inputUlxlyArgs.inputFileName = getDepositCommand.Flags().String(ArgFileName, "", "An ndjson file with deposit data") From 9006c1a6d583da159d7a4ed8391985eee69debff Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Tue, 10 Dec 2024 13:33:06 -0500 Subject: [PATCH 08/24] feat: better logging of revert data --- cmd/ulxly/ulxly.go | 50 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 14dbd69e0..684f52c32 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -170,6 +170,40 @@ func zeroProof() error { return nil } +type JsonError struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data"` +} + +func logAndReturnJsonError(err error) error { + if err == nil { + return nil + } + + var jsonError JsonError + jsonErrorBytes, jsErr := json.Marshal(err) + if jsErr != nil { + log.Error().Err(err).Msg("Unable to interact with the bridge contract") + return err + } + + jsErr = json.Unmarshal(jsonErrorBytes, &jsonError) + if jsErr != nil { + log.Error().Err(err).Msg("Unable to interact with the bridge contract") + return err + } + + log.Error(). + Err(err). + Str("message", jsonError.Message). + Int("code", jsonError.Code). + Interface("data", jsonError.Data). + Msg("Unable to interact with bridge contract") + + return err +} + func bridgeAsset(cmd *cobra.Command) error { bridgeAddress := *inputUlxlyArgs.bridgeAddress privateKey := *inputUlxlyArgs.privateKey @@ -208,8 +242,7 @@ func bridgeAsset(cmd *cobra.Command) error { bridgeTxn, err := bridgeV2.BridgeAsset(auth, destinationNetwork, toAddress, value, tokenAddress, isForced, callData) if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err + return logAndReturnJsonError(err) } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -253,8 +286,7 @@ func bridgeMessage(cmd *cobra.Command) error { bridgeTxn, err := bridgeV2.BridgeMessage(auth, destinationNetwork, toAddress, isForced, callData) if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err + return logAndReturnJsonError(err) } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -301,8 +333,7 @@ func bridgeWETHMessage(cmd *cobra.Command) error { bridgeTxn, err := bridgeV2.BridgeMessageWETH(auth, destinationNetwork, toAddress, value, isForced, callData) if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err + return logAndReturnJsonError(err) } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -362,8 +393,7 @@ func claimAsset(cmd *cobra.Command) error { } claimTxn, err := bridgeV2.ClaimAsset(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err + return logAndReturnJsonError(err) } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) @@ -416,8 +446,7 @@ func claimMessage(cmd *cobra.Command) error { //ClaimMessage(opts *bind.TransactOpts, smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { claimTxn, err := bridgeV2.ClaimMessage(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) if err != nil { - log.Error().Err(err).Msg("Unable to interact with bridge contract") - return err + return logAndReturnJsonError(err) } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) @@ -1051,6 +1080,7 @@ func init() { ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey) ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL) ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress) + // TODO this should be optional and we should use the private key to determine the destination address ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgDestAddress) // bridge specific args From cd1a382d655bc025682cc64551f26bee0f24e62e Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Tue, 10 Dec 2024 13:44:31 -0500 Subject: [PATCH 09/24] fix: issue with bridge address --- cmd/ulxly/ulxly.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 684f52c32..e2b7a4802 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -87,8 +87,11 @@ func readDeposit(cmd *cobra.Command) error { if err != nil { return err } + bridgeAddress, err := cmd.Flags().GetString(ArgBridgeAddress) + if err != nil { + return err + } - bridgeAddress := *inputUlxlyArgs.bridgeAddress toBlock := *inputUlxlyArgs.toBlock fromBlock := *inputUlxlyArgs.fromBlock filter := *inputUlxlyArgs.filterSize @@ -1068,11 +1071,11 @@ func init() { } // Arguments for both bridge and claim + inputUlxlyArgs.rpcURL = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgRPCURL, "", "the URL of the RPC to send the transaction") + inputUlxlyArgs.bridgeAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgBridgeAddress, "", "the address of the lxly bridge") inputUlxlyArgs.gasLimit = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgGasLimit, 0, "force a gas limit when sending a transaction") inputUlxlyArgs.chainID = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgChainID, "", "set the chain id to be used in the transaction") inputUlxlyArgs.privateKey = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgPrivateKey, "", "the hex encoded private key to be used when sending the tx") - inputUlxlyArgs.rpcURL = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgRPCURL, "", "the URL of the RPC to send the transaction") - inputUlxlyArgs.bridgeAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgBridgeAddress, "", "the address of the lxly bridge") inputUlxlyArgs.destAddress = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgDestAddress, "", "the address where the bridge will be sent to") inputUlxlyArgs.timeout = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgTimeout, 60, "the amount of time to wait while trying to confirm a transaction receipt") inputUlxlyArgs.gasPrice = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgGasPrice, "", "the gas price to be used") @@ -1107,6 +1110,7 @@ func init() { inputUlxlyArgs.toBlock = getDepositCommand.Flags().Uint64(ArgToBlock, 0, "The end of the range of blocks to retrieve") inputUlxlyArgs.filterSize = getDepositCommand.Flags().Uint64(ArgFilterSize, 1000, "The batch size for individual filter queries") getDepositCommand.Flags().String(ArgRPCURL, "", "The RPC URL to read deposit data") + getDepositCommand.Flags().String(ArgBridgeAddress, "", "The address of the ulxly bridge") getDepositCommand.MarkFlagRequired(ArgFromBlock) getDepositCommand.MarkFlagRequired(ArgToBlock) getDepositCommand.MarkFlagRequired(ArgRPCURL) From d4875fc49b294a5f6e9f1868000808578ba1924e Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Tue, 10 Dec 2024 15:51:06 -0500 Subject: [PATCH 10/24] fix: token too long for large bridge messages --- cmd/ulxly/ulxly.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index e2b7a4802..663c3d589 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -507,6 +507,8 @@ func getInputData(args []string) ([]byte, error) { func readDeposits(rawDeposits []byte, depositNumber uint32) error { buf := bytes.NewBuffer(rawDeposits) scanner := bufio.NewScanner(buf) + scannerBuf := make([]byte, 0) + scanner.Buffer(scannerBuf, 1024*1024) imt := new(IMT) imt.Init() seenDeposit := make(map[uint32]common.Hash, 0) @@ -539,7 +541,12 @@ func readDeposits(rawDeposits []byte, depositNumber uint32) error { break } } + if err := scanner.Err(); err != nil { + log.Error().Err(err).Msg("there was an error reading the deposit file") + return err + } + log.Info().Msg("finished") p := imt.GetProof(depositNumber) fmt.Println(p.String()) return nil @@ -1105,7 +1112,6 @@ func init() { ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL) // Args that are just for the get deposit command - inputUlxlyArgs.inputFileName = getDepositCommand.Flags().String(ArgFileName, "", "An ndjson file with deposit data") inputUlxlyArgs.fromBlock = getDepositCommand.Flags().Uint64(ArgFromBlock, 0, "The start of the range of blocks to retrieve") inputUlxlyArgs.toBlock = getDepositCommand.Flags().Uint64(ArgToBlock, 0, "The end of the range of blocks to retrieve") inputUlxlyArgs.filterSize = getDepositCommand.Flags().Uint64(ArgFilterSize, 1000, "The batch size for individual filter queries") @@ -1115,6 +1121,10 @@ func init() { getDepositCommand.MarkFlagRequired(ArgToBlock) getDepositCommand.MarkFlagRequired(ArgRPCURL) + // Args for the proof command + inputUlxlyArgs.inputFileName = proofCommand.Flags().String(ArgFileName, "", "An ndjson file with deposit data") + inputUlxlyArgs.depositNumber = proofCommand.Flags().Uint64(ArgDepositCount, 0, "The deposit number to generate a proof for") + // Top Level ULxLyCmd.AddCommand(ulxlyBridgeAndClaimCmd) ULxLyCmd.AddCommand(emptyProofCommand) From 7319e96d8f472d317bbaa21ba535f0a3c26e554c Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Tue, 10 Dec 2024 18:11:27 -0500 Subject: [PATCH 11/24] fix: handling 0x prefix encoding issue --- cmd/ulxly/ulxly.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 663c3d589..57bf52c66 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -237,7 +237,7 @@ func bridgeAsset(cmd *cobra.Command) error { value, _ := big.NewInt(0).SetString(amount, 0) tokenAddress := common.HexToAddress(tokenAddr) - callData := common.Hex2Bytes(callDataString) + callData := common.Hex2Bytes(strings.TrimPrefix(callDataString, "0x")) if tokenAddress == common.HexToAddress("0x0000000000000000000000000000000000000000") { auth.Value = value @@ -281,7 +281,7 @@ func bridgeMessage(cmd *cobra.Command) error { value, _ := big.NewInt(0).SetString(amount, 0) tokenAddress := common.HexToAddress(tokenAddr) - callData := common.Hex2Bytes(callDataString) + callData := common.Hex2Bytes(strings.TrimPrefix(callDataString, "0x")) if tokenAddress == common.HexToAddress("0x0000000000000000000000000000000000000000") { auth.Value = value @@ -332,7 +332,7 @@ func bridgeWETHMessage(cmd *cobra.Command) error { } value, _ := big.NewInt(0).SetString(amount, 0) - callData := common.Hex2Bytes(callDataString) + callData := common.Hex2Bytes(strings.TrimPrefix(callDataString, "0x")) bridgeTxn, err := bridgeV2.BridgeMessageWETH(auth, destinationNetwork, toAddress, value, isForced, callData) if err != nil { @@ -889,10 +889,20 @@ func getDeposit(bridgeServiceDepositsEndpoint string) (globalIndex *big.Int, ori originAddress = common.HexToAddress(bridgeDeposit.Deposit.OrigAddr) globalIndex.SetString(bridgeDeposit.Deposit.GlobalIndex, 10) amount.SetString(bridgeDeposit.Deposit.Amount, 10) - metadata = common.Hex2Bytes(bridgeDeposit.Deposit.Metadata) + + metadata = common.Hex2Bytes(strings.TrimPrefix(bridgeDeposit.Deposit.Metadata, "0x")) leafType = bridgeDeposit.Deposit.LeafType claimDestNetwork = bridgeDeposit.Deposit.DestNet claimOriginalNetwork = bridgeDeposit.Deposit.OrigNet + log.Info(). + Stringer("globalIndex", globalIndex). + Stringer("originAddress", originAddress). + Stringer("amount", amount). + Str("metadata", bridgeDeposit.Deposit.Metadata). + Uint8("leafType", leafType). + Uint32("claimDestNetwork", claimDestNetwork). + Uint32("claimOriginalNetwork", claimOriginalNetwork). + Msg("Got Deposit") return globalIndex, originAddress, amount, metadata, leafType, claimDestNetwork, claimOriginalNetwork, nil } From 7a3919b1fc75a29c41f2827edca214de56b94b0f Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Fri, 13 Dec 2024 16:34:57 -0500 Subject: [PATCH 12/24] feat: intial implementation for claim-everything --- cmd/ulxly/ulxly.go | 269 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 222 insertions(+), 47 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 57bf52c66..c1c0a35fd 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -13,6 +13,7 @@ import ( "math/big" "net/http" "os" + "strconv" "strings" "time" @@ -60,26 +61,27 @@ type BridgeProof struct { RollupExitRoot string `json:"rollup_exit_root"` } `json:"proof"` } - type BridgeDeposit struct { - Deposit struct { - LeafType uint8 `json:"leaf_type"` - OrigNet uint32 `json:"orig_net"` - OrigAddr string `json:"orig_addr"` - Amount string `json:"amount"` - DestNet uint32 `json:"dest_net"` - DestAddr string `json:"dest_addr"` - BlockNum string `json:"block_num"` - DepositCnt uint32 `json:"deposit_cnt"` - NetworkID uint32 `json:"network_id"` - TxHash string `json:"tx_hash"` - ClaimTxHash string `json:"claim_tx_hash"` - Metadata string `json:"metadata"` - ReadyForClaim bool `json:"ready_for_claim"` - GlobalIndex string `json:"global_index"` - } `json:"deposit"` - Code *int `json:"code"` - Message *string `json:"message"` + LeafType uint8 `json:"leaf_type"` + OrigNet uint32 `json:"orig_net"` + OrigAddr string `json:"orig_addr"` + Amount string `json:"amount"` + DestNet uint32 `json:"dest_net"` + DestAddr string `json:"dest_addr"` + BlockNum string `json:"block_num"` + DepositCnt uint32 `json:"deposit_cnt"` + NetworkID uint32 `json:"network_id"` + TxHash string `json:"tx_hash"` + ClaimTxHash string `json:"claim_tx_hash"` + Metadata string `json:"metadata"` + ReadyForClaim bool `json:"ready_for_claim"` + GlobalIndex string `json:"global_index"` +} + +type BridgeDepositResponse struct { + Deposit BridgeDeposit `json:"deposit"` + Code *int `json:"code"` + Message *string `json:"message"` } func readDeposit(cmd *cobra.Command) error { @@ -455,6 +457,137 @@ func claimMessage(cmd *cobra.Command) error { return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) } +func getBridgeServiceURLs() (map[uint32]string, error) { + bridgeServiceUrls := *inputUlxlyArgs.bridgeServiceURLs + urlMap := make(map[uint32]string) + for _, mapping := range bridgeServiceUrls { + pieces := strings.Split(mapping, "=") + if len(pieces) != 2 { + return nil, fmt.Errorf("bridge service url mapping should contain a networkid and url separated by an equal sign. Got: %s", mapping) + } + networkId, err := strconv.ParseInt(pieces[0], 10, 32) + if err != nil { + return nil, err + } + urlMap[uint32(networkId)] = pieces[1] + } + return urlMap, nil +} + +func claimEverything(cmd *cobra.Command) error { + privateKey := *inputUlxlyArgs.privateKey + gasLimit := *inputUlxlyArgs.gasLimit + chainID := *inputUlxlyArgs.chainID + timeoutTxnReceipt := *inputUlxlyArgs.timeout + bridgeAddress := *inputUlxlyArgs.bridgeAddress + destinationAddress := *inputUlxlyArgs.destAddress + RPCURL := *inputUlxlyArgs.rpcURL + limit := *inputUlxlyArgs.bridgeLimit + urls, err := getBridgeServiceURLs() + if err != nil { + return err + } + + allDeposits := make([]BridgeDeposit, 0) + + for _, bridgeServiceUrl := range urls { + deposits, bErr := getDepositsForAddress(fmt.Sprintf("%s/bridges/%s?limit=%d", bridgeServiceUrl, destinationAddress, limit)) + if bErr != nil { + return bErr + } + allDeposits = append(allDeposits, deposits...) + } + + client, err := ethclient.DialContext(cmd.Context(), RPCURL) + if err != nil { + log.Error().Err(err).Msg("Unable to Dial RPC") + return err + } + defer client.Close() + + bridgeContract, _, opts, err := generateTransactionPayload(cmd.Context(), client, bridgeAddress, privateKey, gasLimit, destinationAddress, chainID) + if err != nil { + return err + } + + currentNetworkID, err := bridgeContract.NetworkID(nil) + if err != nil { + return err + } + log.Info().Uint32("networkID", currentNetworkID).Msg("detected current networkid") + for _, deposit := range allDeposits { + if deposit.DestNet != currentNetworkID { + log.Debug().Uint32("destination_network", deposit.DestNet).Msg("discarding deposit for different network") + continue + } + if deposit.ClaimTxHash != "" { + log.Info().Str("txhash", deposit.ClaimTxHash).Msg("It looks like this tx was already claimed") + } + claimTx, dErr := claimSingleDeposit(bridgeContract, opts, deposit, urls, currentNetworkID) + if dErr != nil { + continue + } + dErr = WaitMineTransaction(cmd.Context(), client, claimTx, timeoutTxnReceipt) + if dErr != nil { + log.Error().Err(dErr).Msg("error while waiting for tx to main") + } + } + + return nil +} + +func claimSingleDeposit(bridgeContract *ulxly.Ulxly, opts *bind.TransactOpts, deposit BridgeDeposit, bridgeURLs map[uint32]string, currentNetworkID uint32) (*types.Transaction, error) { + networkIDForBridgeService := deposit.NetworkID + if deposit.NetworkID == 0 { + networkIDForBridgeService = currentNetworkID + } + bridgeUrl, hasKey := bridgeURLs[networkIDForBridgeService] + if !hasKey { + return nil, fmt.Errorf("we don't have a bridge service url for network: %d", deposit.DestNet) + } + bridgeServiceProofEndpoint := fmt.Sprintf("%s/merkle-proof?deposit_cnt=%d&net_id=%d", bridgeUrl, deposit.DepositCnt, deposit.NetworkID) + merkleProofArray, rollupMerkleProofArray, mainExitRoot, rollupExitRoot := getMerkleProofsExitRoots(bridgeServiceProofEndpoint) + if len(mainExitRoot) != 32 || len(rollupExitRoot) != 32 { + log.Warn(). + Uint32("DepositCnt", deposit.DepositCnt). + Uint32("OrigNet", deposit.OrigNet). + Uint32("DestNet", deposit.DestNet). + Uint32("NetworkID", deposit.NetworkID). + Str("OrigAddr", deposit.OrigAddr). + Str("DestAddr", deposit.DestAddr). + Msg("deposit can't be claimed!") + return nil, fmt.Errorf("the exit roots from the bridse service were empty: %s", bridgeServiceProofEndpoint) + } + + globalIndex, isValid := new(big.Int).SetString(deposit.GlobalIndex, 10) + if !isValid { + return nil, fmt.Errorf("global index %s is not a valid integer", deposit.GlobalIndex) + } + amount, isValid := new(big.Int).SetString(deposit.Amount, 10) + if !isValid { + return nil, fmt.Errorf("amount %s is not a valid integer", deposit.Amount) + } + + originAddress := common.HexToAddress(deposit.OrigAddr) + toAddress := common.HexToAddress(deposit.DestAddr) + metadata := common.Hex2Bytes(strings.TrimPrefix(deposit.Metadata, "0x")) + + var claimTx *types.Transaction + var err error + if deposit.LeafType == 0 { + claimTx, err = bridgeContract.ClaimAsset(opts, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), deposit.OrigNet, originAddress, deposit.DestNet, toAddress, amount, metadata) + } else { + claimTx, err = bridgeContract.ClaimMessage(opts, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), deposit.OrigNet, originAddress, deposit.DestNet, toAddress, amount, metadata) + } + + if err != nil { + return nil, logAndReturnJsonError(err) + } + log.Info().Stringer("txhash", claimTx.Hash()).Msg("sent claim") + + return claimTx, nil +} + // Wait for the transaction to be mined func WaitMineTransaction(ctx context.Context, client *ethclient.Client, tx *types.Transaction, txTimeout uint64) error { if inputUlxlyArgs.dryRun != nil && *inputUlxlyArgs.dryRun { @@ -758,6 +891,7 @@ func generateTransactionPayload(ctx context.Context, client *ethclient.Client, u privateKey, err := crypto.HexToECDSA(ulxlyInputArgPvtKey) if err != nil { log.Error().Err(err).Msg("Unable to retrieve private key") + return } // value := big.NewInt(*ulxlyInputArgs.Amount) @@ -831,7 +965,7 @@ func getMerkleProofsExitRoots(bridgeServiceProofEndpoint string) (merkleProofArr merkleProof = append(merkleProof, [32]byte(byteMP)) } if len(merkleProof) == 0 { - log.Error().Msg("The Merkle Proofs cannot be retrieved, double check the input arguments and try again.") + log.Error().Str("url", bridgeServiceProofEndpoint).Msg("The Merkle Proofs cannot be retrieved, double check the input arguments and try again.") return } merkleProofArray = [32][32]byte(merkleProof) @@ -864,7 +998,7 @@ func getDeposit(bridgeServiceDepositsEndpoint string) (globalIndex *big.Int, ori log.Error().Err(err) return } - var bridgeDeposit BridgeDeposit + var bridgeDeposit BridgeDepositResponse err = json.Unmarshal(bodyBridgeDeposit, &bridgeDeposit) // Parse []byte to go struct pointer, and shadow err variable if err != nil { log.Error().Err(err).Msg("Can not unmarshal JSON") @@ -905,6 +1039,30 @@ func getDeposit(bridgeServiceDepositsEndpoint string) (globalIndex *big.Int, ori Msg("Got Deposit") return globalIndex, originAddress, amount, metadata, leafType, claimDestNetwork, claimOriginalNetwork, nil } +func getDepositsForAddress(bridgeRequestUrl string) ([]BridgeDeposit, error) { + var resp struct { + Deposits []BridgeDeposit `json:"deposits"` + Total int `json:"total_cnt,string"` + } + httpResp, err := http.Get(bridgeRequestUrl) + if err != nil { + return nil, err + } + defer httpResp.Body.Close() + respBytes, err := io.ReadAll(httpResp.Body) + if err != nil { + return nil, err + } + err = json.Unmarshal(respBytes, &resp) + if err != nil { + return nil, err + } + if len(resp.Deposits) != resp.Total { + log.Warn().Int("total_deposits", resp.Total).Int("retrieved_deposits", len(resp.Deposits)).Msg("not all deposits were retrieved") + } + + return resp.Deposits, nil +} //go:embed BridgeAssetUsage.md var bridgeAssetUsage string @@ -951,29 +1109,31 @@ var ulxlyClaimCmd = &cobra.Command{ } type ulxlyArgs struct { - gasLimit *uint64 - chainID *string - privateKey *string - value *string - rpcURL *string - bridgeAddress *string - destNetwork *uint32 - destAddress *string - tokenAddress *string - forceUpdate *bool - callData *string - timeout *uint64 - depositCount *uint64 - depositNetwork *uint64 - bridgeServiceURL *string - inputFileName *string - fromBlock *uint64 - toBlock *uint64 - filterSize *uint64 - depositNumber *uint64 - globalIndex *string - gasPrice *string - dryRun *bool + gasLimit *uint64 + chainID *string + privateKey *string + value *string + rpcURL *string + bridgeAddress *string + destNetwork *uint32 + destAddress *string + tokenAddress *string + forceUpdate *bool + callData *string + timeout *uint64 + depositCount *uint64 + depositNetwork *uint64 + bridgeServiceURL *string + inputFileName *string + fromBlock *uint64 + toBlock *uint64 + filterSize *uint64 + depositNumber *uint64 + globalIndex *string + gasPrice *string + dryRun *bool + bridgeServiceURLs *[]string + bridgeLimit *int } var inputUlxlyArgs = ulxlyArgs{} @@ -984,6 +1144,7 @@ var ( bridgeMessageWETHCommand *cobra.Command claimAssetCommand *cobra.Command claimMessageCommand *cobra.Command + claimEverythingCommand *cobra.Command emptyProofCommand *cobra.Command zeroProofCommand *cobra.Command proofCommand *cobra.Command @@ -1013,6 +1174,8 @@ const ( ArgGlobalIndex = "global-index" ArgDryRun = "dry-run" ArgGasPrice = "gas-price" + ArgBridgeMappings = "bridge-service-map" + ArgBridgeLimit = "bridge-limit" ) func init() { @@ -1046,11 +1209,18 @@ func init() { } claimMessageCommand = &cobra.Command{ Use: "message", - Short: "perform a claim of a given message in the birdge", + Short: "perform a claim of a given message in the bridge", RunE: func(cmd *cobra.Command, args []string) error { return claimMessage(cmd) }, } + claimEverythingCommand = &cobra.Command{ + Use: "claim-everything", + Short: "attempt to claim any unclaimed deposits", + RunE: func(cmd *cobra.Command, args []string) error { + return claimEverything(cmd) + }, + } emptyProofCommand = &cobra.Command{ Use: "empty-proof", Short: "create an empty proof", @@ -1116,11 +1286,15 @@ func init() { inputUlxlyArgs.depositNetwork = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositNetwork, 0, "the rollup id of the network where the bridge is being claimed") inputUlxlyArgs.bridgeServiceURL = ulxlyClaimCmd.PersistentFlags().String(ArgBridgeServiceURL, "", "the URL of the bridge service") inputUlxlyArgs.globalIndex = ulxlyClaimCmd.PersistentFlags().String(ArgGlobalIndex, "", "an override of the global index value") - ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount) ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork) ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL) + // Claim Everything Helper Command + inputUlxlyArgs.bridgeServiceURLs = claimEverythingCommand.Flags().StringSlice(ArgBridgeMappings, nil, "Mappings between network ids and bridge service urls. E.g. '1=http://network-1-bridgeurl,7=http://network-2-bridgeurl'") + inputUlxlyArgs.bridgeLimit = claimEverythingCommand.Flags().Int(ArgBridgeLimit, 25, "Limit the number or responses returned by the bridge service when claiming") + claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings) + // Args that are just for the get deposit command inputUlxlyArgs.fromBlock = getDepositCommand.Flags().Uint64(ArgFromBlock, 0, "The start of the range of blocks to retrieve") inputUlxlyArgs.toBlock = getDepositCommand.Flags().Uint64(ArgToBlock, 0, "The end of the range of blocks to retrieve") @@ -1144,10 +1318,12 @@ func init() { ULxLyCmd.AddCommand(ulxlxBridgeCmd) ULxLyCmd.AddCommand(ulxlyClaimCmd) + ULxLyCmd.AddCommand(claimEverythingCommand) // Bridge and Claim ulxlyBridgeAndClaimCmd.AddCommand(ulxlxBridgeCmd) ulxlyBridgeAndClaimCmd.AddCommand(ulxlyClaimCmd) + ulxlyBridgeAndClaimCmd.AddCommand(claimEverythingCommand) // Bridge ulxlxBridgeCmd.AddCommand(bridgeAssetCommand) @@ -1157,5 +1333,4 @@ func init() { // Claim ulxlyClaimCmd.AddCommand(claimAssetCommand) ulxlyClaimCmd.AddCommand(claimMessageCommand) - } From b88ca09d89154871f430d7fd78717e62ad171575 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Wed, 18 Dec 2024 09:57:12 -0500 Subject: [PATCH 13/24] feat: adding more logging --- cmd/ulxly/ulxly.go | 52 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index c1c0a35fd..9251b5c6e 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -78,6 +78,11 @@ type BridgeDeposit struct { GlobalIndex string `json:"global_index"` } +type DepositID struct { + DepositCnt uint32 `json:"deposit_cnt"` + NetworkID uint32 `json:"network_id"` +} + type BridgeDepositResponse struct { Deposit BridgeDeposit `json:"deposit"` Code *int `json:"code"` @@ -483,19 +488,36 @@ func claimEverything(cmd *cobra.Command) error { destinationAddress := *inputUlxlyArgs.destAddress RPCURL := *inputUlxlyArgs.rpcURL limit := *inputUlxlyArgs.bridgeLimit + offset := *inputUlxlyArgs.bridgeOffset urls, err := getBridgeServiceURLs() if err != nil { return err } - allDeposits := make([]BridgeDeposit, 0) + depositMap := make(map[DepositID]*BridgeDeposit) for _, bridgeServiceUrl := range urls { - deposits, bErr := getDepositsForAddress(fmt.Sprintf("%s/bridges/%s?limit=%d", bridgeServiceUrl, destinationAddress, limit)) + deposits, bErr := getDepositsForAddress(fmt.Sprintf("%s/bridges/%s?offset=%d&limit=%d", bridgeServiceUrl, destinationAddress, offset, limit)) if bErr != nil { return bErr } - allDeposits = append(allDeposits, deposits...) + for idx, deposit := range deposits { + depId := DepositID{ + DepositCnt: deposit.DepositCnt, + NetworkID: deposit.NetworkID, + } + _, hasKey := depositMap[depId] + // if we haven't seen this deposit at all, we'll store it + if !hasKey { + depositMap[depId] = &deposits[idx] + continue + } + + // if this new deposit is ready for claim OR it has already been claimed we should over ride the exisitng value + if deposit.ReadyForClaim || deposit.ClaimTxHash != "" { + depositMap[depId] = &deposits[idx] + } + } } client, err := ethclient.DialContext(cmd.Context(), RPCURL) @@ -515,16 +537,24 @@ func claimEverything(cmd *cobra.Command) error { return err } log.Info().Uint32("networkID", currentNetworkID).Msg("detected current networkid") - for _, deposit := range allDeposits { + for _, deposit := range depositMap { if deposit.DestNet != currentNetworkID { log.Debug().Uint32("destination_network", deposit.DestNet).Msg("discarding deposit for different network") continue } if deposit.ClaimTxHash != "" { log.Info().Str("txhash", deposit.ClaimTxHash).Msg("It looks like this tx was already claimed") + continue } - claimTx, dErr := claimSingleDeposit(bridgeContract, opts, deposit, urls, currentNetworkID) + claimTx, dErr := claimSingleDeposit(bridgeContract, opts, *deposit, urls, currentNetworkID) if dErr != nil { + log.Warn().Err(dErr).Uint32("DepositCnt", deposit.DepositCnt). + Uint32("OrigNet", deposit.OrigNet). + Uint32("DestNet", deposit.DestNet). + Uint32("NetworkID", deposit.NetworkID). + Str("OrigAddr", deposit.OrigAddr). + Str("DestAddr", deposit.DestAddr). + Msg("There was an error claiming") continue } dErr = WaitMineTransaction(cmd.Context(), client, claimTx, timeoutTxnReceipt) @@ -581,6 +611,14 @@ func claimSingleDeposit(bridgeContract *ulxly.Ulxly, opts *bind.TransactOpts, de } if err != nil { + log.Warn(). + Uint32("DepositCnt", deposit.DepositCnt). + Uint32("OrigNet", deposit.OrigNet). + Uint32("DestNet", deposit.DestNet). + Uint32("NetworkID", deposit.NetworkID). + Str("OrigAddr", deposit.OrigAddr). + Str("DestAddr", deposit.DestAddr). + Msg("attempt to claim deposit failed") return nil, logAndReturnJsonError(err) } log.Info().Stringer("txhash", claimTx.Hash()).Msg("sent claim") @@ -1039,6 +1077,7 @@ func getDeposit(bridgeServiceDepositsEndpoint string) (globalIndex *big.Int, ori Msg("Got Deposit") return globalIndex, originAddress, amount, metadata, leafType, claimDestNetwork, claimOriginalNetwork, nil } + func getDepositsForAddress(bridgeRequestUrl string) ([]BridgeDeposit, error) { var resp struct { Deposits []BridgeDeposit `json:"deposits"` @@ -1134,6 +1173,7 @@ type ulxlyArgs struct { dryRun *bool bridgeServiceURLs *[]string bridgeLimit *int + bridgeOffset *int } var inputUlxlyArgs = ulxlyArgs{} @@ -1176,6 +1216,7 @@ const ( ArgGasPrice = "gas-price" ArgBridgeMappings = "bridge-service-map" ArgBridgeLimit = "bridge-limit" + ArgBridgeOffset = "bridge-offset" ) func init() { @@ -1293,6 +1334,7 @@ func init() { // Claim Everything Helper Command inputUlxlyArgs.bridgeServiceURLs = claimEverythingCommand.Flags().StringSlice(ArgBridgeMappings, nil, "Mappings between network ids and bridge service urls. E.g. '1=http://network-1-bridgeurl,7=http://network-2-bridgeurl'") inputUlxlyArgs.bridgeLimit = claimEverythingCommand.Flags().Int(ArgBridgeLimit, 25, "Limit the number or responses returned by the bridge service when claiming") + inputUlxlyArgs.bridgeOffset = claimEverythingCommand.Flags().Int(ArgBridgeOffset, 0, "The offset to specify for pagination of the underlying bridge service deposits") claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings) // Args that are just for the get deposit command From 7de0bfb69eb4279f7505783023685d27839b6d96 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Fri, 20 Dec 2024 14:42:27 -0500 Subject: [PATCH 14/24] feat: additional logging --- cmd/ulxly/ulxly.go | 75 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 9251b5c6e..4cf980031 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/ethereum/go-ethereum" "io" "math/big" "net/http" @@ -186,7 +187,38 @@ type JsonError struct { Data interface{} `json:"data"` } -func logAndReturnJsonError(err error) error { +func logAndReturnJsonError(cmd *cobra.Command, client *ethclient.Client, tx *types.Transaction, opts *bind.TransactOpts, err error) error { + // in case the error came down to gas estimation, we can sometimes get more information by doing a call + _, callErr := client.CallContract(cmd.Context(), ethereum.CallMsg{ + From: opts.From, + To: tx.To(), + Gas: tx.Gas(), + GasPrice: tx.GasPrice(), + GasFeeCap: tx.GasFeeCap(), + GasTipCap: tx.GasTipCap(), + Value: tx.Value(), + Data: tx.Data(), + AccessList: tx.AccessList(), + BlobGasFeeCap: tx.BlobGasFeeCap(), + BlobHashes: tx.BlobHashes(), + }, nil) + + if *inputUlxlyArgs.dryRun { + castCmd := "cast call" + castCmd += fmt.Sprintf(" --rpc-url %s", *inputUlxlyArgs.rpcURL) + castCmd += fmt.Sprintf(" --from %s", opts.From.String()) + castCmd += fmt.Sprintf(" --gas-limit %d", tx.Gas()) + if tx.Type() == types.LegacyTxType { + castCmd += fmt.Sprintf(" --gas-price %s", tx.GasPrice().String()) + } else { + castCmd += fmt.Sprintf(" --gas-price %s", tx.GasFeeCap().String()) + castCmd += fmt.Sprintf(" --priority-gas-price %s", tx.GasTipCap().String()) + } + castCmd += fmt.Sprintf(" --value %s", tx.Value().String()) + castCmd += fmt.Sprintf(" %s", tx.To().String()) + castCmd += fmt.Sprintf(" %s", common.Bytes2Hex(tx.Data())) + log.Info().Str("cmd", castCmd).Msg("use this command to replicate the call") + } if err == nil { return nil } @@ -204,12 +236,17 @@ func logAndReturnJsonError(err error) error { return err } - log.Error(). + errLog := log.Error(). Err(err). Str("message", jsonError.Message). Int("code", jsonError.Code). - Interface("data", jsonError.Data). - Msg("Unable to interact with bridge contract") + Interface("data", jsonError.Data) + + if callErr != nil { + errLog = errLog.Err(callErr) + } + + errLog.Msg("Unable to interact with bridge contract") return err } @@ -252,7 +289,7 @@ func bridgeAsset(cmd *cobra.Command) error { bridgeTxn, err := bridgeV2.BridgeAsset(auth, destinationNetwork, toAddress, value, tokenAddress, isForced, callData) if err != nil { - return logAndReturnJsonError(err) + return logAndReturnJsonError(cmd, client, bridgeTxn, auth, err) } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -296,7 +333,7 @@ func bridgeMessage(cmd *cobra.Command) error { bridgeTxn, err := bridgeV2.BridgeMessage(auth, destinationNetwork, toAddress, isForced, callData) if err != nil { - return logAndReturnJsonError(err) + return logAndReturnJsonError(cmd, client, bridgeTxn, auth, err) } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -343,7 +380,7 @@ func bridgeWETHMessage(cmd *cobra.Command) error { bridgeTxn, err := bridgeV2.BridgeMessageWETH(auth, destinationNetwork, toAddress, value, isForced, callData) if err != nil { - return logAndReturnJsonError(err) + return logAndReturnJsonError(cmd, client, bridgeTxn, auth, err) } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -403,7 +440,7 @@ func claimAsset(cmd *cobra.Command) error { } claimTxn, err := bridgeV2.ClaimAsset(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) if err != nil { - return logAndReturnJsonError(err) + return logAndReturnJsonError(cmd, client, claimTxn, auth, err) } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) @@ -456,7 +493,7 @@ func claimMessage(cmd *cobra.Command) error { //ClaimMessage(opts *bind.TransactOpts, smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { claimTxn, err := bridgeV2.ClaimMessage(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) if err != nil { - return logAndReturnJsonError(err) + return logAndReturnJsonError(cmd, client, claimTxn, auth, err) } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) @@ -531,7 +568,6 @@ func claimEverything(cmd *cobra.Command) error { if err != nil { return err } - currentNetworkID, err := bridgeContract.NetworkID(nil) if err != nil { return err @@ -546,7 +582,7 @@ func claimEverything(cmd *cobra.Command) error { log.Info().Str("txhash", deposit.ClaimTxHash).Msg("It looks like this tx was already claimed") continue } - claimTx, dErr := claimSingleDeposit(bridgeContract, opts, *deposit, urls, currentNetworkID) + claimTx, dErr := claimSingleDeposit(cmd, client, bridgeContract, opts, *deposit, urls, currentNetworkID) if dErr != nil { log.Warn().Err(dErr).Uint32("DepositCnt", deposit.DepositCnt). Uint32("OrigNet", deposit.OrigNet). @@ -566,7 +602,7 @@ func claimEverything(cmd *cobra.Command) error { return nil } -func claimSingleDeposit(bridgeContract *ulxly.Ulxly, opts *bind.TransactOpts, deposit BridgeDeposit, bridgeURLs map[uint32]string, currentNetworkID uint32) (*types.Transaction, error) { +func claimSingleDeposit(cmd *cobra.Command, client *ethclient.Client, bridgeContract *ulxly.Ulxly, opts *bind.TransactOpts, deposit BridgeDeposit, bridgeURLs map[uint32]string, currentNetworkID uint32) (*types.Transaction, error) { networkIDForBridgeService := deposit.NetworkID if deposit.NetworkID == 0 { networkIDForBridgeService = currentNetworkID @@ -586,7 +622,7 @@ func claimSingleDeposit(bridgeContract *ulxly.Ulxly, opts *bind.TransactOpts, de Str("OrigAddr", deposit.OrigAddr). Str("DestAddr", deposit.DestAddr). Msg("deposit can't be claimed!") - return nil, fmt.Errorf("the exit roots from the bridse service were empty: %s", bridgeServiceProofEndpoint) + return nil, fmt.Errorf("the exit roots from the bridge service were empty: %s", bridgeServiceProofEndpoint) } globalIndex, isValid := new(big.Int).SetString(deposit.GlobalIndex, 10) @@ -619,7 +655,7 @@ func claimSingleDeposit(bridgeContract *ulxly.Ulxly, opts *bind.TransactOpts, de Str("OrigAddr", deposit.OrigAddr). Str("DestAddr", deposit.DestAddr). Msg("attempt to claim deposit failed") - return nil, logAndReturnJsonError(err) + return nil, logAndReturnJsonError(cmd, client, claimTx, opts, err) } log.Info().Stringer("txhash", claimTx.Hash()).Msg("sent claim") @@ -629,7 +665,8 @@ func claimSingleDeposit(bridgeContract *ulxly.Ulxly, opts *bind.TransactOpts, de // Wait for the transaction to be mined func WaitMineTransaction(ctx context.Context, client *ethclient.Client, tx *types.Transaction, txTimeout uint64) error { if inputUlxlyArgs.dryRun != nil && *inputUlxlyArgs.dryRun { - log.Info().Msg("Skipping receipt check. Dry run is enabled") + txJson, _ := tx.MarshalJSON() + log.Info().RawJSON("tx", txJson).Msg("Skipping receipt check. Dry run is enabled") return nil } txnMinedTimer := time.NewTimer(time.Duration(txTimeout) * time.Second) @@ -934,14 +971,6 @@ func generateTransactionPayload(ctx context.Context, client *ethclient.Client, u // value := big.NewInt(*ulxlyInputArgs.Amount) gasLimit := ulxlyInputArgGasLimit - // gasPrice, err := client.SuggestGasPrice(ctx) // This call is done automatically if it is not set - // if err != nil { - // log.Error().Err(err).Msg("Cannot get suggested gas price") - // } - // gasTipCap, err := client.SuggestGasTipCap(ctx) - // if err != nil { - // log.Error().Err(err).Msg("Cannot get suggested gas tip cap") - // } chainID := new(big.Int) // For manual input of chainID, use the user's input From cfd970c63656d6352068280a9fd3aac0762bf139 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Fri, 20 Dec 2024 14:54:17 -0500 Subject: [PATCH 15/24] feat: surpressing error logs --- cmd/ulxly/ulxly.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 4cf980031..eabdeebac 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -246,6 +246,11 @@ func logAndReturnJsonError(cmd *cobra.Command, client *ethclient.Client, tx *typ errLog = errLog.Err(callErr) } + if errCode, isValid := jsonError.Data.(string); isValid && errCode == "0x646cf558" { + // I don't want to bother with the additional error logging for previously claimed deposits + return err + } + errLog.Msg("Unable to interact with bridge contract") return err From 971e19fc00422a16d0ac808f71403cda0b75a996 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Fri, 20 Dec 2024 15:07:59 -0500 Subject: [PATCH 16/24] fix: null tx --- cmd/ulxly/ulxly.go | 87 ++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index eabdeebac..655b056fa 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -188,37 +188,42 @@ type JsonError struct { } func logAndReturnJsonError(cmd *cobra.Command, client *ethclient.Client, tx *types.Transaction, opts *bind.TransactOpts, err error) error { - // in case the error came down to gas estimation, we can sometimes get more information by doing a call - _, callErr := client.CallContract(cmd.Context(), ethereum.CallMsg{ - From: opts.From, - To: tx.To(), - Gas: tx.Gas(), - GasPrice: tx.GasPrice(), - GasFeeCap: tx.GasFeeCap(), - GasTipCap: tx.GasTipCap(), - Value: tx.Value(), - Data: tx.Data(), - AccessList: tx.AccessList(), - BlobGasFeeCap: tx.BlobGasFeeCap(), - BlobHashes: tx.BlobHashes(), - }, nil) - - if *inputUlxlyArgs.dryRun { - castCmd := "cast call" - castCmd += fmt.Sprintf(" --rpc-url %s", *inputUlxlyArgs.rpcURL) - castCmd += fmt.Sprintf(" --from %s", opts.From.String()) - castCmd += fmt.Sprintf(" --gas-limit %d", tx.Gas()) - if tx.Type() == types.LegacyTxType { - castCmd += fmt.Sprintf(" --gas-price %s", tx.GasPrice().String()) - } else { - castCmd += fmt.Sprintf(" --gas-price %s", tx.GasFeeCap().String()) - castCmd += fmt.Sprintf(" --priority-gas-price %s", tx.GasTipCap().String()) + + var callErr error + if tx != nil { + // in case the error came down to gas estimation, we can sometimes get more information by doing a call + _, callErr = client.CallContract(cmd.Context(), ethereum.CallMsg{ + From: opts.From, + To: tx.To(), + Gas: tx.Gas(), + GasPrice: tx.GasPrice(), + GasFeeCap: tx.GasFeeCap(), + GasTipCap: tx.GasTipCap(), + Value: tx.Value(), + Data: tx.Data(), + AccessList: tx.AccessList(), + BlobGasFeeCap: tx.BlobGasFeeCap(), + BlobHashes: tx.BlobHashes(), + }, nil) + + if *inputUlxlyArgs.dryRun { + castCmd := "cast call" + castCmd += fmt.Sprintf(" --rpc-url %s", *inputUlxlyArgs.rpcURL) + castCmd += fmt.Sprintf(" --from %s", opts.From.String()) + castCmd += fmt.Sprintf(" --gas-limit %d", tx.Gas()) + if tx.Type() == types.LegacyTxType { + castCmd += fmt.Sprintf(" --gas-price %s", tx.GasPrice().String()) + } else { + castCmd += fmt.Sprintf(" --gas-price %s", tx.GasFeeCap().String()) + castCmd += fmt.Sprintf(" --priority-gas-price %s", tx.GasTipCap().String()) + } + castCmd += fmt.Sprintf(" --value %s", tx.Value().String()) + castCmd += fmt.Sprintf(" %s", tx.To().String()) + castCmd += fmt.Sprintf(" %s", common.Bytes2Hex(tx.Data())) + log.Info().Str("cmd", castCmd).Msg("use this command to replicate the call") } - castCmd += fmt.Sprintf(" --value %s", tx.Value().String()) - castCmd += fmt.Sprintf(" %s", tx.To().String()) - castCmd += fmt.Sprintf(" %s", common.Bytes2Hex(tx.Data())) - log.Info().Str("cmd", castCmd).Msg("use this command to replicate the call") } + if err == nil { return nil } @@ -293,8 +298,8 @@ func bridgeAsset(cmd *cobra.Command) error { } bridgeTxn, err := bridgeV2.BridgeAsset(auth, destinationNetwork, toAddress, value, tokenAddress, isForced, callData) - if err != nil { - return logAndReturnJsonError(cmd, client, bridgeTxn, auth, err) + if err = logAndReturnJsonError(cmd, client, bridgeTxn, auth, err); err != nil { + return err } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -337,8 +342,8 @@ func bridgeMessage(cmd *cobra.Command) error { } bridgeTxn, err := bridgeV2.BridgeMessage(auth, destinationNetwork, toAddress, isForced, callData) - if err != nil { - return logAndReturnJsonError(cmd, client, bridgeTxn, auth, err) + if err = logAndReturnJsonError(cmd, client, bridgeTxn, auth, err); err != nil { + return err } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -384,8 +389,8 @@ func bridgeWETHMessage(cmd *cobra.Command) error { callData := common.Hex2Bytes(strings.TrimPrefix(callDataString, "0x")) bridgeTxn, err := bridgeV2.BridgeMessageWETH(auth, destinationNetwork, toAddress, value, isForced, callData) - if err != nil { - return logAndReturnJsonError(cmd, client, bridgeTxn, auth, err) + if err = logAndReturnJsonError(cmd, client, bridgeTxn, auth, err); err != nil { + return err } log.Info().Msg("bridgeTxn: " + bridgeTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, bridgeTxn, timeoutTxnReceipt) @@ -444,8 +449,8 @@ func claimAsset(cmd *cobra.Command) error { globalIndex.SetString(globalIndexOverride, 10) } claimTxn, err := bridgeV2.ClaimAsset(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) - if err != nil { - return logAndReturnJsonError(cmd, client, claimTxn, auth, err) + if err = logAndReturnJsonError(cmd, client, claimTxn, auth, err); err != nil { + return err } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) @@ -497,8 +502,8 @@ func claimMessage(cmd *cobra.Command) error { } //ClaimMessage(opts *bind.TransactOpts, smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { claimTxn, err := bridgeV2.ClaimMessage(auth, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), claimOriginalNetwork, originAddress, claimDestNetwork, toAddress, amount, metadata) - if err != nil { - return logAndReturnJsonError(cmd, client, claimTxn, auth, err) + if err = logAndReturnJsonError(cmd, client, claimTxn, auth, err); err != nil { + return err } log.Info().Msg("claimTxn: " + claimTxn.Hash().String()) return WaitMineTransaction(cmd.Context(), client, claimTxn, timeoutTxnReceipt) @@ -651,7 +656,7 @@ func claimSingleDeposit(cmd *cobra.Command, client *ethclient.Client, bridgeCont claimTx, err = bridgeContract.ClaimMessage(opts, merkleProofArray, rollupMerkleProofArray, globalIndex, [32]byte(mainExitRoot), [32]byte(rollupExitRoot), deposit.OrigNet, originAddress, deposit.DestNet, toAddress, amount, metadata) } - if err != nil { + if err = logAndReturnJsonError(cmd, client, claimTx, opts, err); err != nil { log.Warn(). Uint32("DepositCnt", deposit.DepositCnt). Uint32("OrigNet", deposit.OrigNet). @@ -660,7 +665,7 @@ func claimSingleDeposit(cmd *cobra.Command, client *ethclient.Client, bridgeCont Str("OrigAddr", deposit.OrigAddr). Str("DestAddr", deposit.DestAddr). Msg("attempt to claim deposit failed") - return nil, logAndReturnJsonError(cmd, client, claimTx, opts, err) + return nil, err } log.Info().Stringer("txhash", claimTx.Hash()).Msg("sent claim") From 7fa6ed290e13bd027424524737c4b6ea278d9ce8 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Fri, 20 Dec 2024 15:24:43 -0500 Subject: [PATCH 17/24] feat: better defaults for dry running --- cmd/ulxly/ulxly.go | 109 +++++++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 38 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 655b056fa..5830a7f31 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "context" + "crypto/ecdsa" _ "embed" "encoding/binary" "encoding/json" @@ -1187,32 +1188,33 @@ var ulxlyClaimCmd = &cobra.Command{ } type ulxlyArgs struct { - gasLimit *uint64 - chainID *string - privateKey *string - value *string - rpcURL *string - bridgeAddress *string - destNetwork *uint32 - destAddress *string - tokenAddress *string - forceUpdate *bool - callData *string - timeout *uint64 - depositCount *uint64 - depositNetwork *uint64 - bridgeServiceURL *string - inputFileName *string - fromBlock *uint64 - toBlock *uint64 - filterSize *uint64 - depositNumber *uint64 - globalIndex *string - gasPrice *string - dryRun *bool - bridgeServiceURLs *[]string - bridgeLimit *int - bridgeOffset *int + gasLimit *uint64 + chainID *string + privateKey *string + addressOfPrivateKey string + value *string + rpcURL *string + bridgeAddress *string + destNetwork *uint32 + destAddress *string + tokenAddress *string + forceUpdate *bool + callData *string + timeout *uint64 + depositCount *uint64 + depositNetwork *uint64 + bridgeServiceURL *string + inputFileName *string + fromBlock *uint64 + toBlock *uint64 + filterSize *uint64 + depositNumber *uint64 + globalIndex *string + gasPrice *string + dryRun *bool + bridgeServiceURLs *[]string + bridgeLimit *int + bridgeOffset *int } var inputUlxlyArgs = ulxlyArgs{} @@ -1258,45 +1260,76 @@ const ( ArgBridgeOffset = "bridge-offset" ) +func prepInputs(cmd *cobra.Command, args []string) error { + if *inputUlxlyArgs.dryRun && *inputUlxlyArgs.gasLimit == 0 { + dryRunGasLimit := uint64(10_000_000) + inputUlxlyArgs.gasLimit = &dryRunGasLimit + } + pvtKey := strings.TrimPrefix(*inputUlxlyArgs.privateKey, "0x") + + privateKey, err := crypto.HexToECDSA(pvtKey) + if err != nil { + return err + } + publicKey := privateKey.Public() + + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + return fmt.Errorf("cannot assert type: publicKey is not of type *ecdsa.PublicKey") + } + fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA) + inputUlxlyArgs.addressOfPrivateKey = fromAddress.String() + if *inputUlxlyArgs.destAddress == "" { + *inputUlxlyArgs.destAddress = fromAddress.String() + } + return nil +} + func init() { bridgeAssetCommand = &cobra.Command{ - Use: "asset", - Short: "send a single deposit of value or an ERC20 into the bridge", + Use: "asset", + Short: "send a single deposit of value or an ERC20 into the bridge", + PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return bridgeAsset(cmd) }, } bridgeMessageCommand = &cobra.Command{ - Use: "message", - Short: "send some value along with call data into the bridge", + Use: "message", + Short: "send some value along with call data into the bridge", + PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return bridgeMessage(cmd) }, } bridgeMessageWETHCommand = &cobra.Command{ - Use: "weth", - Short: "send some WETH into the bridge", + Use: "weth", + Short: "send some WETH into the bridge", + PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return bridgeWETHMessage(cmd) }, } claimAssetCommand = &cobra.Command{ - Use: "asset", - Short: "perform a claim of a given deposit in the bridge", + Use: "asset", + Short: "perform a claim of a given deposit in the bridge", + PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return claimAsset(cmd) }, } claimMessageCommand = &cobra.Command{ - Use: "message", - Short: "perform a claim of a given message in the bridge", + Use: "message", + Short: "perform a claim of a given message in the bridge", + PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return claimMessage(cmd) }, } claimEverythingCommand = &cobra.Command{ - Use: "claim-everything", - Short: "attempt to claim any unclaimed deposits", + Use: "claim-everything", + Short: "attempt to claim any unclaimed deposits", + PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return claimEverything(cmd) }, From b4ac5bc2433e6cadea4c5e52a2aefbba5bacce5e Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Mon, 6 Jan 2025 11:15:43 -0500 Subject: [PATCH 18/24] fix: dropping flag that should not be needed --- cmd/ulxly/ulxly.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 5830a7f31..5567ca951 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -1383,8 +1383,6 @@ func init() { ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey) ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL) ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress) - // TODO this should be optional and we should use the private key to determine the destination address - ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgDestAddress) // bridge specific args inputUlxlyArgs.forceUpdate = ulxlxBridgeCmd.PersistentFlags().Bool(ArgForceUpdate, true, "indicates if the new global exit root is updated or not") From 969472583c138d396b00d66a5b8f2727acc8009e Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Mon, 6 Jan 2025 11:23:12 -0500 Subject: [PATCH 19/24] fix: some lint issues --- cmd/ulxly/ulxly.go | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 5567ca951..fe63ea5df 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -1285,10 +1285,18 @@ func prepInputs(cmd *cobra.Command, args []string) error { return nil } +func fatalIfError(err error) { + if err != nil { + return + } + log.Fatal().Err(err).Msg("Unexpected error occurred") +} + func init() { bridgeAssetCommand = &cobra.Command{ Use: "asset", Short: "send a single deposit of value or an ERC20 into the bridge", + Long: bridgeAssetUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return bridgeAsset(cmd) @@ -1297,6 +1305,7 @@ func init() { bridgeMessageCommand = &cobra.Command{ Use: "message", Short: "send some value along with call data into the bridge", + Long: bridgeMessageUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return bridgeMessage(cmd) @@ -1305,6 +1314,7 @@ func init() { bridgeMessageWETHCommand = &cobra.Command{ Use: "weth", Short: "send some WETH into the bridge", + Long: bridgeWETHMessageUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return bridgeWETHMessage(cmd) @@ -1313,6 +1323,7 @@ func init() { claimAssetCommand = &cobra.Command{ Use: "asset", Short: "perform a claim of a given deposit in the bridge", + Long: claimAssetUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return claimAsset(cmd) @@ -1321,6 +1332,7 @@ func init() { claimMessageCommand = &cobra.Command{ Use: "message", Short: "perform a claim of a given message in the bridge", + Long: claimMessageUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return claimMessage(cmd) @@ -1358,6 +1370,7 @@ func init() { proofCommand = &cobra.Command{ Use: "proof", Short: "generate a proof for a given range of deposits", + Long: proofUsage, RunE: func(cmd *cobra.Command, args []string) error { return proof(args) }, @@ -1365,6 +1378,7 @@ func init() { getDepositCommand = &cobra.Command{ Use: "get-deposits", Short: "generate ndjson for each bridge deposit over a particular range of blocks", + Long: depositGetUsage, RunE: func(cmd *cobra.Command, args []string) error { return readDeposit(cmd) }, @@ -1380,9 +1394,9 @@ func init() { inputUlxlyArgs.timeout = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgTimeout, 60, "the amount of time to wait while trying to confirm a transaction receipt") inputUlxlyArgs.gasPrice = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgGasPrice, "", "the gas price to be used") inputUlxlyArgs.dryRun = ulxlyBridgeAndClaimCmd.PersistentFlags().Bool(ArgDryRun, false, "do all of the transaction steps but do not send the transaction") - ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey) - ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL) - ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress) + fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey)) + fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL)) + fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress)) // bridge specific args inputUlxlyArgs.forceUpdate = ulxlxBridgeCmd.PersistentFlags().Bool(ArgForceUpdate, true, "indicates if the new global exit root is updated or not") @@ -1390,22 +1404,22 @@ func init() { inputUlxlyArgs.destNetwork = ulxlxBridgeCmd.PersistentFlags().Uint32(ArgDestNetwork, 0, "the rollup id of the destination network") inputUlxlyArgs.tokenAddress = ulxlxBridgeCmd.PersistentFlags().String(ArgTokenAddress, "0x0000000000000000000000000000000000000000", "the address of an ERC20 token to be used") inputUlxlyArgs.callData = ulxlxBridgeCmd.PersistentFlags().String(ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") - ulxlxBridgeCmd.MarkPersistentFlagRequired(ArgDestNetwork) + fatalIfError(ulxlxBridgeCmd.MarkPersistentFlagRequired(ArgDestNetwork)) // Claim specific args inputUlxlyArgs.depositCount = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositCount, 0, "the deposit count of the bridge transaction") inputUlxlyArgs.depositNetwork = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositNetwork, 0, "the rollup id of the network where the bridge is being claimed") inputUlxlyArgs.bridgeServiceURL = ulxlyClaimCmd.PersistentFlags().String(ArgBridgeServiceURL, "", "the URL of the bridge service") inputUlxlyArgs.globalIndex = ulxlyClaimCmd.PersistentFlags().String(ArgGlobalIndex, "", "an override of the global index value") - ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount) - ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork) - ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL) + fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount)) + fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork)) + fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL)) // Claim Everything Helper Command inputUlxlyArgs.bridgeServiceURLs = claimEverythingCommand.Flags().StringSlice(ArgBridgeMappings, nil, "Mappings between network ids and bridge service urls. E.g. '1=http://network-1-bridgeurl,7=http://network-2-bridgeurl'") inputUlxlyArgs.bridgeLimit = claimEverythingCommand.Flags().Int(ArgBridgeLimit, 25, "Limit the number or responses returned by the bridge service when claiming") inputUlxlyArgs.bridgeOffset = claimEverythingCommand.Flags().Int(ArgBridgeOffset, 0, "The offset to specify for pagination of the underlying bridge service deposits") - claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings) + fatalIfError(claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings)) // Args that are just for the get deposit command inputUlxlyArgs.fromBlock = getDepositCommand.Flags().Uint64(ArgFromBlock, 0, "The start of the range of blocks to retrieve") @@ -1413,9 +1427,9 @@ func init() { inputUlxlyArgs.filterSize = getDepositCommand.Flags().Uint64(ArgFilterSize, 1000, "The batch size for individual filter queries") getDepositCommand.Flags().String(ArgRPCURL, "", "The RPC URL to read deposit data") getDepositCommand.Flags().String(ArgBridgeAddress, "", "The address of the ulxly bridge") - getDepositCommand.MarkFlagRequired(ArgFromBlock) - getDepositCommand.MarkFlagRequired(ArgToBlock) - getDepositCommand.MarkFlagRequired(ArgRPCURL) + fatalIfError(getDepositCommand.MarkFlagRequired(ArgFromBlock)) + fatalIfError(getDepositCommand.MarkFlagRequired(ArgToBlock)) + fatalIfError(getDepositCommand.MarkFlagRequired(ArgRPCURL)) // Args for the proof command inputUlxlyArgs.inputFileName = proofCommand.Flags().String(ArgFileName, "", "An ndjson file with deposit data") From 410b2f122d0881cac405ed0c2fc867fc5b0eeffb Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Mon, 6 Jan 2025 11:34:02 -0500 Subject: [PATCH 20/24] fix: generating docs --- cmd/ulxly/ulxly.go | 26 ++--- doc/polycli_ulxly.md | 14 +-- doc/polycli_ulxly__bridge.md | 59 +++++++++++ doc/polycli_ulxly__bridge_asset.md | 121 ++++++++++++++++++++++ doc/polycli_ulxly__bridge_message.md | 113 +++++++++++++++++++++ doc/polycli_ulxly__bridge_weth.md | 115 +++++++++++++++++++++ doc/polycli_ulxly__claim-everything.md | 55 ++++++++++ doc/polycli_ulxly__claim.md | 56 ++++++++++ doc/polycli_ulxly__claim_asset.md | 135 +++++++++++++++++++++++++ doc/polycli_ulxly__claim_message.md | 116 +++++++++++++++++++++ doc/polycli_ulxly_empty-proof.md | 7 +- doc/polycli_ulxly_get-deposits.md | 97 ++++++++++++++++++ doc/polycli_ulxly_proof.md | 8 +- doc/polycli_ulxly_zero-proof.md | 12 +-- 14 files changed, 900 insertions(+), 34 deletions(-) create mode 100644 doc/polycli_ulxly__bridge.md create mode 100644 doc/polycli_ulxly__bridge_asset.md create mode 100644 doc/polycli_ulxly__bridge_message.md create mode 100644 doc/polycli_ulxly__bridge_weth.md create mode 100644 doc/polycli_ulxly__claim-everything.md create mode 100644 doc/polycli_ulxly__claim.md create mode 100644 doc/polycli_ulxly__claim_asset.md create mode 100644 doc/polycli_ulxly__claim_message.md create mode 100644 doc/polycli_ulxly_get-deposits.md diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index fe63ea5df..b8d4ae222 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -1285,11 +1285,11 @@ func prepInputs(cmd *cobra.Command, args []string) error { return nil } -func fatalIfError(err error) { +func ignoreAndLogError(err error) { if err != nil { return } - log.Fatal().Err(err).Msg("Unexpected error occurred") + log.Debug().Err(err).Msg("Unexpected error occurred") } func init() { @@ -1394,9 +1394,9 @@ func init() { inputUlxlyArgs.timeout = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgTimeout, 60, "the amount of time to wait while trying to confirm a transaction receipt") inputUlxlyArgs.gasPrice = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgGasPrice, "", "the gas price to be used") inputUlxlyArgs.dryRun = ulxlyBridgeAndClaimCmd.PersistentFlags().Bool(ArgDryRun, false, "do all of the transaction steps but do not send the transaction") - fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey)) - fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL)) - fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress)) + ignoreAndLogError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey)) + ignoreAndLogError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL)) + ignoreAndLogError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress)) // bridge specific args inputUlxlyArgs.forceUpdate = ulxlxBridgeCmd.PersistentFlags().Bool(ArgForceUpdate, true, "indicates if the new global exit root is updated or not") @@ -1404,22 +1404,22 @@ func init() { inputUlxlyArgs.destNetwork = ulxlxBridgeCmd.PersistentFlags().Uint32(ArgDestNetwork, 0, "the rollup id of the destination network") inputUlxlyArgs.tokenAddress = ulxlxBridgeCmd.PersistentFlags().String(ArgTokenAddress, "0x0000000000000000000000000000000000000000", "the address of an ERC20 token to be used") inputUlxlyArgs.callData = ulxlxBridgeCmd.PersistentFlags().String(ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") - fatalIfError(ulxlxBridgeCmd.MarkPersistentFlagRequired(ArgDestNetwork)) + ignoreAndLogError(ulxlxBridgeCmd.MarkPersistentFlagRequired(ArgDestNetwork)) // Claim specific args inputUlxlyArgs.depositCount = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositCount, 0, "the deposit count of the bridge transaction") inputUlxlyArgs.depositNetwork = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositNetwork, 0, "the rollup id of the network where the bridge is being claimed") inputUlxlyArgs.bridgeServiceURL = ulxlyClaimCmd.PersistentFlags().String(ArgBridgeServiceURL, "", "the URL of the bridge service") inputUlxlyArgs.globalIndex = ulxlyClaimCmd.PersistentFlags().String(ArgGlobalIndex, "", "an override of the global index value") - fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount)) - fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork)) - fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL)) + ignoreAndLogError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount)) + ignoreAndLogError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork)) + ignoreAndLogError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL)) // Claim Everything Helper Command inputUlxlyArgs.bridgeServiceURLs = claimEverythingCommand.Flags().StringSlice(ArgBridgeMappings, nil, "Mappings between network ids and bridge service urls. E.g. '1=http://network-1-bridgeurl,7=http://network-2-bridgeurl'") inputUlxlyArgs.bridgeLimit = claimEverythingCommand.Flags().Int(ArgBridgeLimit, 25, "Limit the number or responses returned by the bridge service when claiming") inputUlxlyArgs.bridgeOffset = claimEverythingCommand.Flags().Int(ArgBridgeOffset, 0, "The offset to specify for pagination of the underlying bridge service deposits") - fatalIfError(claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings)) + ignoreAndLogError(claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings)) // Args that are just for the get deposit command inputUlxlyArgs.fromBlock = getDepositCommand.Flags().Uint64(ArgFromBlock, 0, "The start of the range of blocks to retrieve") @@ -1427,9 +1427,9 @@ func init() { inputUlxlyArgs.filterSize = getDepositCommand.Flags().Uint64(ArgFilterSize, 1000, "The batch size for individual filter queries") getDepositCommand.Flags().String(ArgRPCURL, "", "The RPC URL to read deposit data") getDepositCommand.Flags().String(ArgBridgeAddress, "", "The address of the ulxly bridge") - fatalIfError(getDepositCommand.MarkFlagRequired(ArgFromBlock)) - fatalIfError(getDepositCommand.MarkFlagRequired(ArgToBlock)) - fatalIfError(getDepositCommand.MarkFlagRequired(ArgRPCURL)) + ignoreAndLogError(getDepositCommand.MarkFlagRequired(ArgFromBlock)) + ignoreAndLogError(getDepositCommand.MarkFlagRequired(ArgToBlock)) + ignoreAndLogError(getDepositCommand.MarkFlagRequired(ArgRPCURL)) // Args for the proof command inputUlxlyArgs.inputFileName = proofCommand.Flags().String(ArgFileName, "", "An ndjson file with deposit data") diff --git a/doc/polycli_ulxly.md b/doc/polycli_ulxly.md index f7f37912e..3e0756094 100644 --- a/doc/polycli_ulxly.md +++ b/doc/polycli_ulxly.md @@ -40,15 +40,17 @@ The command also inherits flags from parent commands. ## See also - [polycli](polycli.md) - A Swiss Army knife of blockchain tools. -- [polycli ulxly deposit-claim](polycli_ulxly_deposit-claim.md) - Make a uLxLy claim transaction +- [polycli ulxly bridge](polycli_ulxly_bridge.md) - commands for making deposits to the uLxLy bridge -- [polycli ulxly deposit-get](polycli_ulxly_deposit-get.md) - Get a range of deposits +- [polycli ulxly claim](polycli_ulxly_claim.md) - commands for making claims of deposits from the uLxLy bridge -- [polycli ulxly deposit-new](polycli_ulxly_deposit-new.md) - Make a uLxLy deposit transaction +- [polycli ulxly claim-everything](polycli_ulxly_claim-everything.md) - attempt to claim any unclaimed deposits -- [polycli ulxly empty-proof](polycli_ulxly_empty-proof.md) - print an empty proof structure +- [polycli ulxly empty-proof](polycli_ulxly_empty-proof.md) - create an empty proof -- [polycli ulxly proof](polycli_ulxly_proof.md) - generate a merkle proof +- [polycli ulxly get-deposits](polycli_ulxly_get-deposits.md) - generate ndjson for each bridge deposit over a particular range of blocks -- [polycli ulxly zero-proof](polycli_ulxly_zero-proof.md) - print a proof structure with the zero hashes +- [polycli ulxly proof](polycli_ulxly_proof.md) - generate a proof for a given range of deposits + +- [polycli ulxly zero-proof](polycli_ulxly_zero-proof.md) - create a proof that's filled with zeros diff --git a/doc/polycli_ulxly__bridge.md b/doc/polycli_ulxly__bridge.md new file mode 100644 index 000000000..d4392a615 --- /dev/null +++ b/doc/polycli_ulxly__bridge.md @@ -0,0 +1,59 @@ +# `polycli ulxly bridge` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +commands for making deposits to the uLxLy bridge + +## Flags + +```bash + --call-data string call data to be passed directly with bridge-message or as an ERC20 Permit (default "0x") + --destination-network uint32 the rollup id of the destination network + --force-update-root indicates if the new global exit root is updated or not (default true) + -h, --help help for bridge + --token-address string the address of an ERC20 token to be used (default "0x0000000000000000000000000000000000000000") + --value string the amount in wei to be sent along with the transaction +``` + +The command also inherits flags from parent commands. + +```bash + --bridge-address string the address of the lxly bridge + --chain-id string set the chain id to be used in the transaction + --config string config file (default is $HOME/.polygon-cli.yaml) + --destination-address string the address where the bridge will be sent to + --dry-run do all of the transaction steps but do not send the transaction + --gas-limit uint force a gas limit when sending a transaction + --gas-price string the gas price to be used + --pretty-logs Should logs be in pretty format or JSON (default true) + --private-key string the hex encoded private key to be used when sending the tx + --rpc-url string the URL of the RPC to send the transaction + --transaction-receipt-timeout uint the amount of time to wait while trying to confirm a transaction receipt (default 60) + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly ](polycli_ulxly_.md) - +- [polycli ulxly bridge asset](polycli_ulxly__bridge_asset.md) - send a single deposit of value or an ERC20 into the bridge + +- [polycli ulxly bridge message](polycli_ulxly__bridge_message.md) - send some value along with call data into the bridge + +- [polycli ulxly bridge weth](polycli_ulxly__bridge_weth.md) - send some WETH into the bridge + diff --git a/doc/polycli_ulxly__bridge_asset.md b/doc/polycli_ulxly__bridge_asset.md new file mode 100644 index 000000000..3d68eb6a3 --- /dev/null +++ b/doc/polycli_ulxly__bridge_asset.md @@ -0,0 +1,121 @@ +# `polycli ulxly bridge asset` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +send a single deposit of value or an ERC20 into the bridge + +```bash +polycli ulxly bridge asset [flags] +``` + +## Usage + +This command will attempt to send a deposit transaction to the bridge contract. + +```solidity + /** + * @notice Deposit add a new leaf to the merkle tree + * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call + * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. + * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens + * do not call any external address in that case + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param token Token address, 0 address is reserved for ether + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param permitData Raw data of the call `permit` of the token + */ + function bridgeAsset( + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + address token, + bool forceUpdateGlobalExitRoot, + bytes calldata permitData + ); + +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly bridge-asset \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --gas-limit 300000 \ + --amount 1000000000000000000 \ + --rpc-url http://127.0.0.1:8545 \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --destination-network 1 \ + --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 +``` + +This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +``` + +Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command + + +Failed deposit transactions will output logs like below: + +```bash +Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 +Try increasing the gas limit: +Current gas limit: 100000 +Cumulative gas used for transaction: 98641 +``` + +The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. + +## Flags + +```bash + -h, --help help for asset +``` + +The command also inherits flags from parent commands. + +```bash + --bridge-address string the address of the lxly bridge + --call-data string call data to be passed directly with bridge-message or as an ERC20 Permit (default "0x") + --chain-id string set the chain id to be used in the transaction + --config string config file (default is $HOME/.polygon-cli.yaml) + --destination-address string the address where the bridge will be sent to + --destination-network uint32 the rollup id of the destination network + --dry-run do all of the transaction steps but do not send the transaction + --force-update-root indicates if the new global exit root is updated or not (default true) + --gas-limit uint force a gas limit when sending a transaction + --gas-price string the gas price to be used + --pretty-logs Should logs be in pretty format or JSON (default true) + --private-key string the hex encoded private key to be used when sending the tx + --rpc-url string the URL of the RPC to send the transaction + --token-address string the address of an ERC20 token to be used (default "0x0000000000000000000000000000000000000000") + --transaction-receipt-timeout uint the amount of time to wait while trying to confirm a transaction receipt (default 60) + --value string the amount in wei to be sent along with the transaction + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly bridge](polycli_ulxly__bridge.md) - commands for making deposits to the uLxLy bridge diff --git a/doc/polycli_ulxly__bridge_message.md b/doc/polycli_ulxly__bridge_message.md new file mode 100644 index 000000000..879946c38 --- /dev/null +++ b/doc/polycli_ulxly__bridge_message.md @@ -0,0 +1,113 @@ +# `polycli ulxly bridge message` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +send some value along with call data into the bridge + +```bash +polycli ulxly bridge message [flags] +``` + +## Usage + +This command will attempt to send a deposit transaction to the bridge contract. + +```solidity + /** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ + function bridgeMessage( + uint32 destinationNetwork, + address destinationAddress, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata + ); +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly bridge-message \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --gas-limit 300000 \ + --amount 1000000000000000000 \ + --rpc-url http://127.0.0.1:8545 \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --destination-network 1 \ + --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 + --call-data 0x001010109200090028979743971976836486868648629808961824738090896826764980866fac97863898ca08928fc7279643 +``` + +This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +``` + +Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command + + +Failed deposit transactions will output logs like below: + +```bash +Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 +Try increasing the gas limit: +Current gas limit: 100000 +Cumulative gas used for transaction: 98641 +``` + +The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. + +## Flags + +```bash + -h, --help help for message +``` + +The command also inherits flags from parent commands. + +```bash + --bridge-address string the address of the lxly bridge + --call-data string call data to be passed directly with bridge-message or as an ERC20 Permit (default "0x") + --chain-id string set the chain id to be used in the transaction + --config string config file (default is $HOME/.polygon-cli.yaml) + --destination-address string the address where the bridge will be sent to + --destination-network uint32 the rollup id of the destination network + --dry-run do all of the transaction steps but do not send the transaction + --force-update-root indicates if the new global exit root is updated or not (default true) + --gas-limit uint force a gas limit when sending a transaction + --gas-price string the gas price to be used + --pretty-logs Should logs be in pretty format or JSON (default true) + --private-key string the hex encoded private key to be used when sending the tx + --rpc-url string the URL of the RPC to send the transaction + --token-address string the address of an ERC20 token to be used (default "0x0000000000000000000000000000000000000000") + --transaction-receipt-timeout uint the amount of time to wait while trying to confirm a transaction receipt (default 60) + --value string the amount in wei to be sent along with the transaction + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly bridge](polycli_ulxly__bridge.md) - commands for making deposits to the uLxLy bridge diff --git a/doc/polycli_ulxly__bridge_weth.md b/doc/polycli_ulxly__bridge_weth.md new file mode 100644 index 000000000..5eccf9570 --- /dev/null +++ b/doc/polycli_ulxly__bridge_weth.md @@ -0,0 +1,115 @@ +# `polycli ulxly bridge weth` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +send some WETH into the bridge + +```bash +polycli ulxly bridge weth [flags] +``` + +## Usage + +This command will attempt to send a deposit transaction to the bridge contract. + +```solidity + /** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amountWETH Amount of WETH tokens + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ + function bridgeMessageWETH( + uint32 destinationNetwork, + address destinationAddress, + uint256 amountWETH, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata + ); +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly bridge-message-weth \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --gas-limit 300000 \ + --amount 1000000000000000000 \ + --rpc-url http://127.0.0.1:8545 \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --destination-network 1 \ + --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 + --call-data 0x001010109200090028979743971976836486868648629808961824738090896826764980866fac97863898ca08928fc7279643 +``` + +This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +``` + +Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command + + +Failed deposit transactions will output logs like below: + +```bash +Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 +Try increasing the gas limit: +Current gas limit: 100000 +Cumulative gas used for transaction: 98641 +``` + +The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. + +## Flags + +```bash + -h, --help help for weth +``` + +The command also inherits flags from parent commands. + +```bash + --bridge-address string the address of the lxly bridge + --call-data string call data to be passed directly with bridge-message or as an ERC20 Permit (default "0x") + --chain-id string set the chain id to be used in the transaction + --config string config file (default is $HOME/.polygon-cli.yaml) + --destination-address string the address where the bridge will be sent to + --destination-network uint32 the rollup id of the destination network + --dry-run do all of the transaction steps but do not send the transaction + --force-update-root indicates if the new global exit root is updated or not (default true) + --gas-limit uint force a gas limit when sending a transaction + --gas-price string the gas price to be used + --pretty-logs Should logs be in pretty format or JSON (default true) + --private-key string the hex encoded private key to be used when sending the tx + --rpc-url string the URL of the RPC to send the transaction + --token-address string the address of an ERC20 token to be used (default "0x0000000000000000000000000000000000000000") + --transaction-receipt-timeout uint the amount of time to wait while trying to confirm a transaction receipt (default 60) + --value string the amount in wei to be sent along with the transaction + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly bridge](polycli_ulxly__bridge.md) - commands for making deposits to the uLxLy bridge diff --git a/doc/polycli_ulxly__claim-everything.md b/doc/polycli_ulxly__claim-everything.md new file mode 100644 index 000000000..00e289a19 --- /dev/null +++ b/doc/polycli_ulxly__claim-everything.md @@ -0,0 +1,55 @@ +# `polycli ulxly claim-everything` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +attempt to claim any unclaimed deposits + +```bash +polycli ulxly claim-everything [flags] +``` + +## Flags + +```bash + --bridge-limit int Limit the number or responses returned by the bridge service when claiming (default 25) + --bridge-offset int The offset to specify for pagination of the underlying bridge service deposits + --bridge-service-map strings Mappings between network ids and bridge service urls. E.g. '1=http://network-1-bridgeurl,7=http://network-2-bridgeurl' + -h, --help help for claim-everything +``` + +The command also inherits flags from parent commands. + +```bash + --bridge-address string the address of the lxly bridge + --chain-id string set the chain id to be used in the transaction + --config string config file (default is $HOME/.polygon-cli.yaml) + --destination-address string the address where the bridge will be sent to + --dry-run do all of the transaction steps but do not send the transaction + --gas-limit uint force a gas limit when sending a transaction + --gas-price string the gas price to be used + --pretty-logs Should logs be in pretty format or JSON (default true) + --private-key string the hex encoded private key to be used when sending the tx + --rpc-url string the URL of the RPC to send the transaction + --transaction-receipt-timeout uint the amount of time to wait while trying to confirm a transaction receipt (default 60) + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly ](polycli_ulxly_.md) - diff --git a/doc/polycli_ulxly__claim.md b/doc/polycli_ulxly__claim.md new file mode 100644 index 000000000..e38dd9fd0 --- /dev/null +++ b/doc/polycli_ulxly__claim.md @@ -0,0 +1,56 @@ +# `polycli ulxly claim` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +commands for making claims of deposits from the uLxLy bridge + +## Flags + +```bash + --bridge-service-url string the URL of the bridge service + --deposit-count uint the deposit count of the bridge transaction + --deposit-network uint the rollup id of the network where the bridge is being claimed + --global-index string an override of the global index value + -h, --help help for claim +``` + +The command also inherits flags from parent commands. + +```bash + --bridge-address string the address of the lxly bridge + --chain-id string set the chain id to be used in the transaction + --config string config file (default is $HOME/.polygon-cli.yaml) + --destination-address string the address where the bridge will be sent to + --dry-run do all of the transaction steps but do not send the transaction + --gas-limit uint force a gas limit when sending a transaction + --gas-price string the gas price to be used + --pretty-logs Should logs be in pretty format or JSON (default true) + --private-key string the hex encoded private key to be used when sending the tx + --rpc-url string the URL of the RPC to send the transaction + --transaction-receipt-timeout uint the amount of time to wait while trying to confirm a transaction receipt (default 60) + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly ](polycli_ulxly_.md) - +- [polycli ulxly claim asset](polycli_ulxly__claim_asset.md) - perform a claim of a given deposit in the bridge + +- [polycli ulxly claim message](polycli_ulxly__claim_message.md) - perform a claim of a given message in the bridge + diff --git a/doc/polycli_ulxly__claim_asset.md b/doc/polycli_ulxly__claim_asset.md new file mode 100644 index 000000000..13e209c70 --- /dev/null +++ b/doc/polycli_ulxly__claim_asset.md @@ -0,0 +1,135 @@ +# `polycli ulxly claim asset` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +perform a claim of a given deposit in the bridge + +```bash +polycli ulxly claim asset [flags] +``` + +## Usage + +This command will attempt to send a claim transaction to the bridge contract. + +```solidity + /** + * @notice Verify merkle proof and withdraw tokens/ether + * @param smtProofLocalExitRoot Smt proof to proof the leaf against the network exit root + * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root + * @param globalIndex Global index is defined as: + * | 191 bits | 1 bit | 32 bits | 32 bits | + * | 0 | mainnetFlag | rollupIndex | localRootIndex | + * note that only the rollup index will be used only in case the mainnet flag is 0 + * note that global index do not assert the unused bits to 0. + * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract + * to avoid possible synch attacks + * @param mainnetExitRoot Mainnet exit root + * @param rollupExitRoot Rollup exit root + * @param originNetwork Origin network + * @param originTokenAddress Origin token address, 0 address is reserved for ether + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param metadata Abi encoded metadata if any, empty otherwise + */ + function claimAsset( + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originTokenAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata + ); + +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly deposit-claim \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --claim-index 0 \ + --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ + --claim-network 0 \ + --rpc-url http://127.0.0.1:32790 \ + --bridge-service-url http://127.0.0.1:32804 +``` + +This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b +``` + +Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` + + +Failed deposit transactions will output logs like below: + +```bash +Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a +``` + +The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: + +```! +curl http://127.0.0.1:32790 \ +-X POST \ +-H "Content-Type: application/json" \ +--data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' +``` + +## Flags + +```bash + -h, --help help for asset +``` + +The command also inherits flags from parent commands. + +```bash + --bridge-address string the address of the lxly bridge + --bridge-service-url string the URL of the bridge service + --chain-id string set the chain id to be used in the transaction + --config string config file (default is $HOME/.polygon-cli.yaml) + --deposit-count uint the deposit count of the bridge transaction + --deposit-network uint the rollup id of the network where the bridge is being claimed + --destination-address string the address where the bridge will be sent to + --dry-run do all of the transaction steps but do not send the transaction + --gas-limit uint force a gas limit when sending a transaction + --gas-price string the gas price to be used + --global-index string an override of the global index value + --pretty-logs Should logs be in pretty format or JSON (default true) + --private-key string the hex encoded private key to be used when sending the tx + --rpc-url string the URL of the RPC to send the transaction + --transaction-receipt-timeout uint the amount of time to wait while trying to confirm a transaction receipt (default 60) + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly claim](polycli_ulxly__claim.md) - commands for making claims of deposits from the uLxLy bridge diff --git a/doc/polycli_ulxly__claim_message.md b/doc/polycli_ulxly__claim_message.md new file mode 100644 index 000000000..582387c36 --- /dev/null +++ b/doc/polycli_ulxly__claim_message.md @@ -0,0 +1,116 @@ +# `polycli ulxly claim message` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +perform a claim of a given message in the bridge + +```bash +polycli ulxly claim message [flags] +``` + +## Usage + +This command will attempt to send a claim transaction to the bridge contract. + +```solidity + /** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ + function bridgeMessage( + uint32 destinationNetwork, + address destinationAddress, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata + ); + +``` + +Each transaction will require manual input of parameters. Example usage: + +```bash +polycli ulxly deposit-claim \ + --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ + --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ + --claim-index 0 \ + --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ + --claim-network 0 \ + --rpc-url http://127.0.0.1:32790 \ + --bridge-service-url http://127.0.0.1:32804 +``` + +This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. +Successful deposit transaction will output logs like below: + +```bash +Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b +``` + +Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` + + +Failed deposit transactions will output logs like below: + +```bash +Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a +``` + +The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: + +```! +curl http://127.0.0.1:32790 \ +-X POST \ +-H "Content-Type: application/json" \ +--data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' +``` + +## Flags + +```bash + -h, --help help for message +``` + +The command also inherits flags from parent commands. + +```bash + --bridge-address string the address of the lxly bridge + --bridge-service-url string the URL of the bridge service + --chain-id string set the chain id to be used in the transaction + --config string config file (default is $HOME/.polygon-cli.yaml) + --deposit-count uint the deposit count of the bridge transaction + --deposit-network uint the rollup id of the network where the bridge is being claimed + --destination-address string the address where the bridge will be sent to + --dry-run do all of the transaction steps but do not send the transaction + --gas-limit uint force a gas limit when sending a transaction + --gas-price string the gas price to be used + --global-index string an override of the global index value + --pretty-logs Should logs be in pretty format or JSON (default true) + --private-key string the hex encoded private key to be used when sending the tx + --rpc-url string the URL of the RPC to send the transaction + --transaction-receipt-timeout uint the amount of time to wait while trying to confirm a transaction receipt (default 60) + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly claim](polycli_ulxly__claim.md) - commands for making claims of deposits from the uLxLy bridge diff --git a/doc/polycli_ulxly_empty-proof.md b/doc/polycli_ulxly_empty-proof.md index 0d138202d..31e2dccc7 100644 --- a/doc/polycli_ulxly_empty-proof.md +++ b/doc/polycli_ulxly_empty-proof.md @@ -11,7 +11,7 @@ ## Description -print an empty proof structure +create an empty proof ```bash polycli ulxly empty-proof [flags] @@ -19,10 +19,7 @@ polycli ulxly empty-proof [flags] ## Usage -Use this command to print an empty proof response that's filled with -zero-valued siblings like -0x0000000000000000000000000000000000000000000000000000000000000000. This -can be useful when you need to submit a dummy proof. +Use this command to print an empty proof response that's filled with zero-valued siblings like 0x0000000000000000000000000000000000000000000000000000000000000000. This can be useful when you need to submit a dummy proof. ## Flags ```bash diff --git a/doc/polycli_ulxly_get-deposits.md b/doc/polycli_ulxly_get-deposits.md new file mode 100644 index 000000000..8711e98db --- /dev/null +++ b/doc/polycli_ulxly_get-deposits.md @@ -0,0 +1,97 @@ +# `polycli ulxly get-deposits` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +generate ndjson for each bridge deposit over a particular range of blocks + +```bash +polycli ulxly get-deposits [flags] +``` + +## Usage + +This command will attempt to scan a range of blocks and look for uLxLy +Bridge Events. This is is the specific signature that we're interested +in: + +```solidity + /** + * @dev Emitted when bridge assets or messages to another network + */ + event BridgeEvent( + uint8 leafType, + uint32 originNetwork, + address originAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes metadata, + uint32 depositCount + ); + +``` + +If you're looking at the raw topics from on chain or in an explorer, this is the associated value: + +`0x501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b` + +Each event that we counter will be parsed and written as JSON to +stdout. Example usage: + +```bash +polycli ulxly deposit-get \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --rpc-url https://eth-sepolia.g.alchemy.com/v2/demo \ + --from-block 4880876 \ + --to-block 6028159 \ + --filter-size 9999 > cardona-4880876-to-6028159.ndjson +``` + +This command would look for bridge events from block `4880876` to +block `6028159` in increments of `9999` blocks at a time for the +contract address `0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582`. The +output will be written as newline delimited JSON. + +This command is very specific for the ulxly bridge and it's meant to +serve as the input to the proof command. + + + +## Flags + +```bash + --bridge-address string The address of the ulxly bridge + --filter-size uint The batch size for individual filter queries (default 1000) + --from-block uint The start of the range of blocks to retrieve + -h, --help help for get-deposits + --rpc-url string The RPC URL to read deposit data + --to-block uint The end of the range of blocks to retrieve +``` + +The command also inherits flags from parent commands. + +```bash + --config string config file (default is $HOME/.polygon-cli.yaml) + --pretty-logs Should logs be in pretty format or JSON (default true) + -v, --verbosity int 0 - Silent + 100 Panic + 200 Fatal + 300 Error + 400 Warning + 500 Info + 600 Debug + 700 Trace (default 500) +``` + +## See also + +- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the lxly bridge diff --git a/doc/polycli_ulxly_proof.md b/doc/polycli_ulxly_proof.md index 5e7e00720..77eeba1b9 100644 --- a/doc/polycli_ulxly_proof.md +++ b/doc/polycli_ulxly_proof.md @@ -11,7 +11,7 @@ ## Description -generate a merkle proof +generate a proof for a given range of deposits ```bash polycli ulxly proof [flags] @@ -95,9 +95,9 @@ that the leaf is part of the given merkle root. ## Flags ```bash - --deposit-number uint32 The deposit that we would like to prove - --file-name string The filename with ndjson data of deposits - -h, --help help for proof + --deposit-count uint The deposit number to generate a proof for + --file-name string An ndjson file with deposit data + -h, --help help for proof ``` The command also inherits flags from parent commands. diff --git a/doc/polycli_ulxly_zero-proof.md b/doc/polycli_ulxly_zero-proof.md index c9bd4296c..db4436241 100644 --- a/doc/polycli_ulxly_zero-proof.md +++ b/doc/polycli_ulxly_zero-proof.md @@ -11,7 +11,7 @@ ## Description -print a proof structure with the zero hashes +create a proof that's filled with zeros ```bash polycli ulxly zero-proof [flags] @@ -20,11 +20,11 @@ polycli ulxly zero-proof [flags] ## Usage Use this command to print a proof response that's filled with the zero -hashes. This values are very helpful for debugging because it would -tell you how populated the tree is and roughly which leaves and -siblings are empty. It's also helpful for sanity checking a proof -response to understand if the hashed value is part of the zero hashes -or if it's actually an intermediate hash. + hashes. This values are very helpful for debugging because it would + tell you how populated the tree is and roughly which leaves and + siblings are empty. It's also helpful for sanity checking a proof + response to understand if the hashed value is part of the zero hashes + or if it's actually an intermediate hash. ## Flags ```bash From 0f4cc0957d90b534c07ac3379cc32919d009a20f Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Mon, 6 Jan 2025 16:06:00 -0500 Subject: [PATCH 21/24] docs: updating some of the examples and docs --- README.md | 2 +- cmd/ulxly/BridgeAssetUsage.md | 97 ++++++++++-------- cmd/ulxly/BridgeMessageUsage.md | 87 +++++++++------- cmd/ulxly/BridgeWETHMessageUsage.md | 72 +++++-------- cmd/ulxly/ClaimAssetUsage.md | 128 +++++++++++------------ cmd/ulxly/ClaimMessageUsage.md | 111 ++++++++++++-------- cmd/ulxly/ulxly.go | 51 +++++----- doc/polycli.md | 2 +- doc/polycli_ulxly.md | 10 +- doc/polycli_ulxly__bridge.md | 8 +- doc/polycli_ulxly__bridge_asset.md | 102 ++++++++++--------- doc/polycli_ulxly__bridge_message.md | 91 ++++++++++------- doc/polycli_ulxly__bridge_weth.md | 76 +++++--------- doc/polycli_ulxly__claim-everything.md | 2 +- doc/polycli_ulxly__claim.md | 8 +- doc/polycli_ulxly__claim_asset.md | 135 +++++++++++++------------ doc/polycli_ulxly__claim_message.md | 119 +++++++++++++--------- doc/polycli_ulxly_empty-proof.md | 2 +- doc/polycli_ulxly_get-deposits.md | 2 +- doc/polycli_ulxly_proof.md | 2 +- doc/polycli_ulxly_zero-proof.md | 2 +- 21 files changed, 587 insertions(+), 522 deletions(-) diff --git a/README.md b/README.md index 35f8bf6bf..0c8f7ba89 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Note: Do not modify this section! It is auto-generated by `cobra` using `make ge - [polycli signer](doc/polycli_signer.md) - Utilities for security signing transactions -- [polycli ulxly](doc/polycli_ulxly.md) - Utilities for interacting with the lxly bridge +- [polycli ulxly](doc/polycli_ulxly.md) - Utilities for interacting with the uLxLy bridge - [polycli version](doc/polycli_version.md) - Get the current version of this application diff --git a/cmd/ulxly/BridgeAssetUsage.md b/cmd/ulxly/BridgeAssetUsage.md index eac962d79..f0fd14bc0 100644 --- a/cmd/ulxly/BridgeAssetUsage.md +++ b/cmd/ulxly/BridgeAssetUsage.md @@ -1,61 +1,70 @@ -This command will attempt to send a deposit transaction to the bridge contract. +This command will directly attempt to make a deposit on the uLxLy bridge. This call responds to the method defined below: ```solidity - /** - * @notice Deposit add a new leaf to the merkle tree - * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call - * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. - * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens - * do not call any external address in that case - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amount Amount of tokens - * @param token Token address, 0 address is reserved for ether - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param permitData Raw data of the call `permit` of the token - */ - function bridgeAsset( - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - address token, - bool forceUpdateGlobalExitRoot, - bytes calldata permitData - ); - +/** + * @notice Deposit add a new leaf to the merkle tree + * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call + * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. + * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens + * do not call any external address in that case + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param token Token address, 0 address is reserved for ether + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param permitData Raw data of the call `permit` of the token + */ +function bridgeAsset( + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + address token, + bool forceUpdateGlobalExitRoot, + bytes calldata permitData +) public payable virtual ifNotEmergencyState nonReentrant { ``` -Each transaction will require manual input of parameters. Example usage: +The source of this method is [here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L198-L219). +Below is an example of how we would make simple bridge of native ETH from Sepolia (L1) into Cardona (L2). ```bash -polycli ulxly bridge-asset \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --gas-limit 300000 \ - --amount 1000000000000000000 \ - --rpc-url http://127.0.0.1:8545 \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --destination-network 1 \ - --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 +polycli ulxly bridge asset \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 1 \ + --value 10000000000000000 \ + --rpc-url https://sepolia.drpc.org ``` -This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: +[This](https://sepolia.etherscan.io/tx/0xf57b8171b2f62dce3eedbe3e50d5ee8413d61438af64286b5017ed9d5d154816) is the transaction that was created and mined from running this command. + +Here is another example that will bridge a [test ERC20 token](https://sepolia.etherscan.io/address/0xC92AeF5873d058a76685140F3328B0DED79733Af) from Sepolia (L1) into Cardona (L2). In order for this to work, the token would need to have an [approval](https://sepolia.etherscan.io/tx/0x028513b13a2a7899de4db56e60d1dad66c7b7e29f91c54f385fdfdfc8f14b8b4#eventlog) for the bridge to spend tokens for that particular user. ```bash -Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +polycli ulxly bridge asset \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 1 \ + --value 10000000000000000 \ + --token-address 0xC92AeF5873d058a76685140F3328B0DED79733Af \ + --destination-address 0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 \ + --rpc-url https://sepolia.drpc.org ``` -Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command - +[This](https://sepolia.etherscan.io/tx/0x8ed1c2c0f2e994c86867f401c86fea3c709a28a18629d473cf683049f176fa93) is the transaction that was created and mined from running this command. -Failed deposit transactions will output logs like below: +Assuming you have funds on L2, a bridge from L2 to L1 looks pretty much the same. +The command below will bridge `123456` of the native ETH on Cardona (L2) back to network 0 which corresponds to Sepolia (L1). ```bash -Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 -Try increasing the gas limit: -Current gas limit: 100000 -Cumulative gas used for transaction: 98641 +polycli ulxly bridge asset \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 0 \ + --value 123456 \ + --destination-address 0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 \ + --rpc-url https://rpc.cardona.zkevm-rpc.com ``` -The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. +[This](https://cardona-zkevm.polygonscan.com/tx/0x0294dae3cfb26881e5dde9f182531aa5be0818956d029d50e9872543f020df2e) is the transaction that was created and mined from running this command. \ No newline at end of file diff --git a/cmd/ulxly/BridgeMessageUsage.md b/cmd/ulxly/BridgeMessageUsage.md index 77aa8dced..0650833ad 100644 --- a/cmd/ulxly/BridgeMessageUsage.md +++ b/cmd/ulxly/BridgeMessageUsage.md @@ -1,53 +1,66 @@ -This command will attempt to send a deposit transaction to the bridge contract. +This command is very similar to `polycli ulxly bridge asset`, but instead this is a more generic interface that can be used to transfer ETH and make a contract call. This is the underlying solidity interface that we're referencing. ```solidity - /** - * @notice Bridge message and send ETH value - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param metadata Message metadata - */ - function bridgeMessage( - uint32 destinationNetwork, - address destinationAddress, - bool forceUpdateGlobalExitRoot, - bytes calldata metadata - ); +/** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ +function bridgeMessage( + uint32 destinationNetwork, + address destinationAddress, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata +) external payable ifNotEmergencyState { ``` -Each transaction will require manual input of parameters. Example usage: +The source code for this particular method is [here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L324-L337). + +Below is a simple example of using this command to bridge a small amount of ETH from Sepolia (L1) to Cardona (L2). In this case, we're not including any call data, so it's essentially equivalent to a `bridge asset` call, but the deposit will not be automatically claimed on L2. ```bash -polycli ulxly bridge-message \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --gas-limit 300000 \ - --amount 1000000000000000000 \ - --rpc-url http://127.0.0.1:8545 \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --destination-network 1 \ - --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 - --call-data 0x001010109200090028979743971976836486868648629808961824738090896826764980866fac97863898ca08928fc7279643 +polycli ulxly bridge message \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 1 \ + --value 10000000000000000 \ + --rpc-url https://sepolia.drpc.org ``` -This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: +[This](https://sepolia.etherscan.io/tx/0x1a6e2be69fa65e866889d95403b2fe820f08b6a07b96c6afbde646b8092addb2) is the transaction that was generated and mined from this command. +In most cases, you'll want to specify some `call-data` and a `destination-address` in order for a contract to be called on the destination chain. For example: ```bash -Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +polycli ulxly bridge message \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 1 \ + --destination-address 0xC92AeF5873d058a76685140F3328B0DED79733Af \ + --call-data 0x40c10f190000000000000000000000003878cff9d621064d393eef92bf1e12a944c5ba84000000000000000000000000000000000000000000000000002386f26fc10000 \ + --value 0 \ + --rpc-url https://sepolia.drpc.org ``` +[This](https://sepolia.etherscan.io/tx/0x517b9d827a3a81770d608a6b997e230d992e1e0cabc0fd2797285693b1cc6a9f) is the transaction that was created and mined from running the above command. -Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command - +In this case, I've configured the destination address to be a test contract I've deployed on L2. +```soldity +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity 0.8.20; -Failed deposit transactions will output logs like below: +contract MessageEmitter { + event MessageReceived (address originAddress, uint32 originNetwork, bytes data); -```bash -Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 -Try increasing the gas limit: -Current gas limit: 100000 -Cumulative gas used for transaction: 98641 + function onMessageReceived(address originAddress, uint32 originNetwork, bytes memory data) external payable { + emit MessageReceived(originAddress, originNetwork, data); + } +} ``` -The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. +The idea is to have minimal contract that will meet the expected interface of the bridge contract: https://github.com/0xPolygonHermez/zkevm-contracts/blob/v9.0.0-rc.3-pp/contracts/interfaces/IBridgeMessageReceiver.sol + +In this case, I didn't bother implementing the proxy to an ERC20 or extending some ERC20 contract. I'm just emitting an event to know that the transaction actually fired as expected. +The calldata comes from running this command `cast calldata 'mint(address account, uint256 amount)' 0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 10000000000000000`. Again, in this case no ERC20 will be minted because I didn't set it up. + diff --git a/cmd/ulxly/BridgeWETHMessageUsage.md b/cmd/ulxly/BridgeWETHMessageUsage.md index 5bc7d8097..652ae026c 100644 --- a/cmd/ulxly/BridgeWETHMessageUsage.md +++ b/cmd/ulxly/BridgeWETHMessageUsage.md @@ -1,55 +1,35 @@ -This command will attempt to send a deposit transaction to the bridge contract. +This command is not used very often but can be used on L2 networks that have a gas token. ```solidity - /** - * @notice Bridge message and send ETH value - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amountWETH Amount of WETH tokens - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param metadata Message metadata - */ - function bridgeMessageWETH( - uint32 destinationNetwork, - address destinationAddress, - uint256 amountWETH, - bool forceUpdateGlobalExitRoot, - bytes calldata metadata - ); +/** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amountWETH Amount of WETH tokens + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ +function bridgeMessageWETH( + uint32 destinationNetwork, + address destinationAddress, + uint256 amountWETH, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata +) external ifNotEmergencyState { ``` +[Here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L352-L367) is the source code that corresponds to this interface. -Each transaction will require manual input of parameters. Example usage: +Assuming the network is configured with a gas token, you could call this method like this: ```bash -polycli ulxly bridge-message-weth \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --gas-limit 300000 \ - --amount 1000000000000000000 \ - --rpc-url http://127.0.0.1:8545 \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ +polycli ulxly bridge weth \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --destination-address 0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --value 123456 \ --destination-network 1 \ - --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 - --call-data 0x001010109200090028979743971976836486868648629808961824738090896826764980866fac97863898ca08928fc7279643 + --rpc-url http://l2-rpc-url.invalid \ + --token-address $WETH_ADDRESS ``` -This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: - -```bash -Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 -``` - -Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command - - -Failed deposit transactions will output logs like below: - -```bash -Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 -Try increasing the gas limit: -Current gas limit: 100000 -Cumulative gas used for transaction: 98641 -``` - -The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. diff --git a/cmd/ulxly/ClaimAssetUsage.md b/cmd/ulxly/ClaimAssetUsage.md index 9c53af434..4af32127e 100644 --- a/cmd/ulxly/ClaimAssetUsage.md +++ b/cmd/ulxly/ClaimAssetUsage.md @@ -1,76 +1,80 @@ -This command will attempt to send a claim transaction to the bridge contract. +This command will connect to the bridge service, generate a proof, and then attempt to claim the deposit on which never network is referred to in the `--rpc-url` argument. +This is the corresponding interface in the bridge contract: ```solidity - /** - * @notice Verify merkle proof and withdraw tokens/ether - * @param smtProofLocalExitRoot Smt proof to proof the leaf against the network exit root - * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root - * @param globalIndex Global index is defined as: - * | 191 bits | 1 bit | 32 bits | 32 bits | - * | 0 | mainnetFlag | rollupIndex | localRootIndex | - * note that only the rollup index will be used only in case the mainnet flag is 0 - * note that global index do not assert the unused bits to 0. - * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract - * to avoid possible synch attacks - * @param mainnetExitRoot Mainnet exit root - * @param rollupExitRoot Rollup exit root - * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amount Amount of tokens - * @param metadata Abi encoded metadata if any, empty otherwise - */ - function claimAsset( - bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, - bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, - uint256 globalIndex, - bytes32 mainnetExitRoot, - bytes32 rollupExitRoot, - uint32 originNetwork, - address originTokenAddress, - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - bytes calldata metadata - ); - +/** + * @notice Verify merkle proof and withdraw tokens/ether + * @param smtProofLocalExitRoot Smt proof to proof the leaf against the network exit root + * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root + * @param globalIndex Global index is defined as: + * | 191 bits | 1 bit | 32 bits | 32 bits | + * | 0 | mainnetFlag | rollupIndex | localRootIndex | + * note that only the rollup index will be used only in case the mainnet flag is 0 + * note that global index do not assert the unused bits to 0. + * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract + * to avoid possible synch attacks + * @param mainnetExitRoot Mainnet exit root + * @param rollupExitRoot Rollup exit root + * @param originNetwork Origin network + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param metadata Abi encoded metadata if any, empty otherwise + */ +function claimAsset( + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originTokenAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata +) external ifNotEmergencyState { ``` -Each transaction will require manual input of parameters. Example usage: - -```bash -polycli ulxly deposit-claim \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --claim-index 0 \ - --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ - --claim-network 0 \ - --rpc-url http://127.0.0.1:32790 \ - --bridge-service-url http://127.0.0.1:32804 -``` +[Here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L433-L465) is a direct link to the source code as well. -This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: +In order to claim an asset or a message, you need to know deposit count. Usually this is in the event data of the transaction. Alternatively, you can usually directly attempt to see the pending deposits by querying the bridge API directly. In the case of Cardona, the bridge service is running here: https://bridge-api.cardona.zkevm-rpc.com ```bash -Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b +curl -s https://bridge-api.cardona.zkevm-rpc.com/bridges/0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 | jq '.' ``` -Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` - +In the output of the above command, I can see a deposit that looks like this: +```json +{ + "leaf_type": 0, + "orig_net": 0, + "orig_addr": "0x0000000000000000000000000000000000000000", + "amount": "123456", + "dest_net": 0, + "dest_addr": "0x3878Cff9d621064d393EEF92bF1e12A944c5ba84", + "block_num": "9695587", + "deposit_cnt": 9075, + "network_id": 1, + "tx_hash": "0x0294dae3cfb26881e5dde9f182531aa5be0818956d029d50e9872543f020df2e", + "claim_tx_hash": "", + "metadata": "0x", + "ready_for_claim": true, + "global_index": "9075" +} +``` -Failed deposit transactions will output logs like below: +If we want to claim this deposit, we can use a command like this: ```bash -Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a +polycli ulxly claim asset \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --bridge-service-url https://bridge-api.cardona.zkevm-rpc.com \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --deposit-network 1 \ + --deposit-count 9075 \ + --rpc-url https://sepolia.drpc.org ``` -The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: - -```! -curl http://127.0.0.1:32790 \ --X POST \ --H "Content-Type: application/json" \ ---data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' -``` +[Here](https://sepolia.etherscan.io/tx/0x21fee6e47a3b6733034fb963b20fe7accb0fb168257450f8f0053d6af8e4bc76) is the transaction that was created and mined based on this command. \ No newline at end of file diff --git a/cmd/ulxly/ClaimMessageUsage.md b/cmd/ulxly/ClaimMessageUsage.md index a29823191..5059b8f15 100644 --- a/cmd/ulxly/ClaimMessageUsage.md +++ b/cmd/ulxly/ClaimMessageUsage.md @@ -1,57 +1,84 @@ -This command will attempt to send a claim transaction to the bridge contract. +This command is used to claim a message type deposit. Here is the interface of the method that's being used: ```solidity - /** - * @notice Bridge message and send ETH value - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param metadata Message metadata - */ - function bridgeMessage( - uint32 destinationNetwork, - address destinationAddress, - bool forceUpdateGlobalExitRoot, - bytes calldata metadata - ); - +/** + * @notice Verify merkle proof and execute message + * If the receiving address is an EOA, the call will result as a success + * Which means that the amount of ether will be transferred correctly, but the message + * will not trigger any execution + * @param smtProofLocalExitRoot Smt proof to proof the leaf against the exit root + * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root + * @param globalIndex Global index is defined as: + * | 191 bits | 1 bit | 32 bits | 32 bits | + * | 0 | mainnetFlag | rollupIndex | localRootIndex | + * note that only the rollup index will be used only in case the mainnet flag is 0 + * note that global index do not assert the unused bits to 0. + * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract + * to avoid possible synch attacks + * @param mainnetExitRoot Mainnet exit root + * @param rollupExitRoot Rollup exit root + * @param originNetwork Origin network + * @param originAddress Origin address + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount message value + * @param metadata Abi encoded metadata if any, empty otherwise + */ +function claimMessage( + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata +) external ifNotEmergencyState { ``` -Each transaction will require manual input of parameters. Example usage: - -```bash -polycli ulxly deposit-claim \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --claim-index 0 \ - --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ - --claim-network 0 \ - --rpc-url http://127.0.0.1:32790 \ - --bridge-service-url http://127.0.0.1:32804 -``` +[Here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L588-L623) is a link to the source code. -This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: +This command is essentially identical to `claim asset`, but it's specific to deposits that are of the message leaf type rather than assets. In order to use this command, I'm going to try to claim one of the messages that I sent while testing `polycli ulxly bridge message`. ```bash -Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b +curl -s https://bridge-api.cardona.zkevm-rpc.com/bridges/0xC92AeF5873d058a76685140F3328B0DED79733Af | jq '.' ``` -Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` +This will show me the deposits that are destined for the test contract that I deployed on L2. At the moment here is the deposit I'm interested in: +```json +{ + "leaf_type": 1, + "orig_net": 0, + "orig_addr": "0x3878Cff9d621064d393EEF92bF1e12A944c5ba84", + "amount": "0", + "dest_net": 1, + "dest_addr": "0xC92AeF5873d058a76685140F3328B0DED79733Af", + "block_num": "7435415", + "deposit_cnt": 67305, + "network_id": 0, + "tx_hash": "0x517b9d827a3a81770d608a6b997e230d992e1e0cabc0fd2797285693b1cc6a9f", + "claim_tx_hash": "", + "metadata": "0x40c10f190000000000000000000000003878cff9d621064d393eef92bf1e12a944c5ba84000000000000000000000000000000000000000000000000002386f26fc10000", + "ready_for_claim": true, + "global_index": "18446744073709618921" +} +``` -Failed deposit transactions will output logs like below: +I'm going to use this command to try to claim this message on L2. ```bash -Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a +polycli ulxly claim message \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --bridge-service-url https://bridge-api.cardona.zkevm-rpc.com \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-address 0xC92AeF5873d058a76685140F3328B0DED79733Af \ + --deposit-network 0 \ + --deposit-count 67305 \ + --rpc-url https://rpc.cardona.zkevm-rpc.com ``` -The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: - -```! -curl http://127.0.0.1:32790 \ --X POST \ --H "Content-Type: application/json" \ ---data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' -``` +[Here](https://cardona-zkevm.polygonscan.com/tx/0x6df4c4e43776d703bf1996334a4e1975bb3c124192563c93e3d199d9240dd56f#eventlog) is the transaction that was generated by this command. Everything looks to have worked properly. The `MessageReceived(address,uint32,bytes)` event with signature `0xe97c9b3f13b44bc13bde4743ae654dff72f8dc2ff9ff6070efc5999f77a37716` showed up in the explorer so our contract fired properly when the claim was made. diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index b8d4ae222..cee25a090 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -1166,8 +1166,8 @@ var depositGetUsage string var ULxLyCmd = &cobra.Command{ Use: "ulxly", - Short: "Utilities for interacting with the lxly bridge", - Long: "These are low level tools for directly scanning bridge events and constructing proofs.", + Short: "Utilities for interacting with the uLxLy bridge", + Long: "Basic utility commands for interacting with the bridge contracts, bridge services, and generating proofs", Args: cobra.NoArgs, } var ulxlyBridgeAndClaimCmd = &cobra.Command{ @@ -1177,13 +1177,13 @@ var ulxlyBridgeAndClaimCmd = &cobra.Command{ var ulxlxBridgeCmd = &cobra.Command{ Use: "bridge", - Short: "commands for making deposits to the uLxLy bridge", + Short: "Commands for moving funds and sending messages from one chain to another", Args: cobra.NoArgs, } var ulxlyClaimCmd = &cobra.Command{ Use: "claim", - Short: "commands for making claims of deposits from the uLxLy bridge", + Short: "Commands for claiming deposits on a particular chain", Args: cobra.NoArgs, } @@ -1281,21 +1281,22 @@ func prepInputs(cmd *cobra.Command, args []string) error { inputUlxlyArgs.addressOfPrivateKey = fromAddress.String() if *inputUlxlyArgs.destAddress == "" { *inputUlxlyArgs.destAddress = fromAddress.String() + log.Info().Stringer("destAddress", fromAddress).Msg("No destination address specified. Using private key's address") } return nil } -func ignoreAndLogError(err error) { - if err != nil { +func fatalIfError(err error) { + if err == nil { return } - log.Debug().Err(err).Msg("Unexpected error occurred") + log.Fatal().Err(err).Msg("Unexpected error occurred") } func init() { bridgeAssetCommand = &cobra.Command{ Use: "asset", - Short: "send a single deposit of value or an ERC20 into the bridge", + Short: "Move ETH or an ERC20 between to chains", Long: bridgeAssetUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { @@ -1304,7 +1305,7 @@ func init() { } bridgeMessageCommand = &cobra.Command{ Use: "message", - Short: "send some value along with call data into the bridge", + Short: "Send some ETH along with data from one chain to another chain", Long: bridgeMessageUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { @@ -1313,7 +1314,7 @@ func init() { } bridgeMessageWETHCommand = &cobra.Command{ Use: "weth", - Short: "send some WETH into the bridge", + Short: "For L2's that use a gas token, use this to transfer WETH to another chain", Long: bridgeWETHMessageUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { @@ -1322,7 +1323,7 @@ func init() { } claimAssetCommand = &cobra.Command{ Use: "asset", - Short: "perform a claim of a given deposit in the bridge", + Short: "Claim a deposit", Long: claimAssetUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { @@ -1331,7 +1332,7 @@ func init() { } claimMessageCommand = &cobra.Command{ Use: "message", - Short: "perform a claim of a given message in the bridge", + Short: "Claim a message", Long: claimMessageUsage, PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { @@ -1340,7 +1341,7 @@ func init() { } claimEverythingCommand = &cobra.Command{ Use: "claim-everything", - Short: "attempt to claim any unclaimed deposits", + Short: "Attempt to claim as many deposits and messages as possible", PreRunE: prepInputs, RunE: func(cmd *cobra.Command, args []string) error { return claimEverything(cmd) @@ -1394,9 +1395,9 @@ func init() { inputUlxlyArgs.timeout = ulxlyBridgeAndClaimCmd.PersistentFlags().Uint64(ArgTimeout, 60, "the amount of time to wait while trying to confirm a transaction receipt") inputUlxlyArgs.gasPrice = ulxlyBridgeAndClaimCmd.PersistentFlags().String(ArgGasPrice, "", "the gas price to be used") inputUlxlyArgs.dryRun = ulxlyBridgeAndClaimCmd.PersistentFlags().Bool(ArgDryRun, false, "do all of the transaction steps but do not send the transaction") - ignoreAndLogError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey)) - ignoreAndLogError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL)) - ignoreAndLogError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress)) + fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgPrivateKey)) + fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgRPCURL)) + fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress)) // bridge specific args inputUlxlyArgs.forceUpdate = ulxlxBridgeCmd.PersistentFlags().Bool(ArgForceUpdate, true, "indicates if the new global exit root is updated or not") @@ -1404,22 +1405,22 @@ func init() { inputUlxlyArgs.destNetwork = ulxlxBridgeCmd.PersistentFlags().Uint32(ArgDestNetwork, 0, "the rollup id of the destination network") inputUlxlyArgs.tokenAddress = ulxlxBridgeCmd.PersistentFlags().String(ArgTokenAddress, "0x0000000000000000000000000000000000000000", "the address of an ERC20 token to be used") inputUlxlyArgs.callData = ulxlxBridgeCmd.PersistentFlags().String(ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") - ignoreAndLogError(ulxlxBridgeCmd.MarkPersistentFlagRequired(ArgDestNetwork)) + fatalIfError(ulxlxBridgeCmd.MarkPersistentFlagRequired(ArgDestNetwork)) // Claim specific args inputUlxlyArgs.depositCount = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositCount, 0, "the deposit count of the bridge transaction") - inputUlxlyArgs.depositNetwork = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositNetwork, 0, "the rollup id of the network where the bridge is being claimed") + inputUlxlyArgs.depositNetwork = ulxlyClaimCmd.PersistentFlags().Uint64(ArgDepositNetwork, 0, "the rollup id of the network where the deposit was initially made") inputUlxlyArgs.bridgeServiceURL = ulxlyClaimCmd.PersistentFlags().String(ArgBridgeServiceURL, "", "the URL of the bridge service") inputUlxlyArgs.globalIndex = ulxlyClaimCmd.PersistentFlags().String(ArgGlobalIndex, "", "an override of the global index value") - ignoreAndLogError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount)) - ignoreAndLogError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork)) - ignoreAndLogError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL)) + fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount)) + fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork)) + fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL)) // Claim Everything Helper Command inputUlxlyArgs.bridgeServiceURLs = claimEverythingCommand.Flags().StringSlice(ArgBridgeMappings, nil, "Mappings between network ids and bridge service urls. E.g. '1=http://network-1-bridgeurl,7=http://network-2-bridgeurl'") inputUlxlyArgs.bridgeLimit = claimEverythingCommand.Flags().Int(ArgBridgeLimit, 25, "Limit the number or responses returned by the bridge service when claiming") inputUlxlyArgs.bridgeOffset = claimEverythingCommand.Flags().Int(ArgBridgeOffset, 0, "The offset to specify for pagination of the underlying bridge service deposits") - ignoreAndLogError(claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings)) + fatalIfError(claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings)) // Args that are just for the get deposit command inputUlxlyArgs.fromBlock = getDepositCommand.Flags().Uint64(ArgFromBlock, 0, "The start of the range of blocks to retrieve") @@ -1427,9 +1428,9 @@ func init() { inputUlxlyArgs.filterSize = getDepositCommand.Flags().Uint64(ArgFilterSize, 1000, "The batch size for individual filter queries") getDepositCommand.Flags().String(ArgRPCURL, "", "The RPC URL to read deposit data") getDepositCommand.Flags().String(ArgBridgeAddress, "", "The address of the ulxly bridge") - ignoreAndLogError(getDepositCommand.MarkFlagRequired(ArgFromBlock)) - ignoreAndLogError(getDepositCommand.MarkFlagRequired(ArgToBlock)) - ignoreAndLogError(getDepositCommand.MarkFlagRequired(ArgRPCURL)) + fatalIfError(getDepositCommand.MarkFlagRequired(ArgFromBlock)) + fatalIfError(getDepositCommand.MarkFlagRequired(ArgToBlock)) + fatalIfError(getDepositCommand.MarkFlagRequired(ArgRPCURL)) // Args for the proof command inputUlxlyArgs.inputFileName = proofCommand.Flags().String(ArgFileName, "", "An ndjson file with deposit data") diff --git a/doc/polycli.md b/doc/polycli.md index b0b912134..00657b07f 100644 --- a/doc/polycli.md +++ b/doc/polycli.md @@ -71,7 +71,7 @@ Polycli is a collection of tools that are meant to be useful while building, tes - [polycli signer](polycli_signer.md) - Utilities for security signing transactions -- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the lxly bridge +- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the uLxLy bridge - [polycli version](polycli_version.md) - Get the current version of this application diff --git a/doc/polycli_ulxly.md b/doc/polycli_ulxly.md index 3e0756094..89e265d1a 100644 --- a/doc/polycli_ulxly.md +++ b/doc/polycli_ulxly.md @@ -11,11 +11,11 @@ ## Description -Utilities for interacting with the lxly bridge +Utilities for interacting with the uLxLy bridge ## Usage -These are low level tools for directly scanning bridge events and constructing proofs. +Basic utility commands for interacting with the bridge contracts, bridge services, and generating proofs ## Flags ```bash @@ -40,11 +40,11 @@ The command also inherits flags from parent commands. ## See also - [polycli](polycli.md) - A Swiss Army knife of blockchain tools. -- [polycli ulxly bridge](polycli_ulxly_bridge.md) - commands for making deposits to the uLxLy bridge +- [polycli ulxly bridge](polycli_ulxly_bridge.md) - Commands for moving funds and sending messages from one chain to another -- [polycli ulxly claim](polycli_ulxly_claim.md) - commands for making claims of deposits from the uLxLy bridge +- [polycli ulxly claim](polycli_ulxly_claim.md) - Commands for claiming deposits on a particular chain -- [polycli ulxly claim-everything](polycli_ulxly_claim-everything.md) - attempt to claim any unclaimed deposits +- [polycli ulxly claim-everything](polycli_ulxly_claim-everything.md) - Attempt to claim as many deposits and messages as possible - [polycli ulxly empty-proof](polycli_ulxly_empty-proof.md) - create an empty proof diff --git a/doc/polycli_ulxly__bridge.md b/doc/polycli_ulxly__bridge.md index d4392a615..c643200e3 100644 --- a/doc/polycli_ulxly__bridge.md +++ b/doc/polycli_ulxly__bridge.md @@ -11,7 +11,7 @@ ## Description -commands for making deposits to the uLxLy bridge +Commands for moving funds and sending messages from one chain to another ## Flags @@ -51,9 +51,9 @@ The command also inherits flags from parent commands. ## See also - [polycli ulxly ](polycli_ulxly_.md) - -- [polycli ulxly bridge asset](polycli_ulxly__bridge_asset.md) - send a single deposit of value or an ERC20 into the bridge +- [polycli ulxly bridge asset](polycli_ulxly__bridge_asset.md) - Move ETH or an ERC20 between to chains -- [polycli ulxly bridge message](polycli_ulxly__bridge_message.md) - send some value along with call data into the bridge +- [polycli ulxly bridge message](polycli_ulxly__bridge_message.md) - Send some ETH along with data from one chain to another chain -- [polycli ulxly bridge weth](polycli_ulxly__bridge_weth.md) - send some WETH into the bridge +- [polycli ulxly bridge weth](polycli_ulxly__bridge_weth.md) - For L2's that use a gas token, use this to transfer WETH to another chain diff --git a/doc/polycli_ulxly__bridge_asset.md b/doc/polycli_ulxly__bridge_asset.md index 3d68eb6a3..c8670fd81 100644 --- a/doc/polycli_ulxly__bridge_asset.md +++ b/doc/polycli_ulxly__bridge_asset.md @@ -11,7 +11,7 @@ ## Description -send a single deposit of value or an ERC20 into the bridge +Move ETH or an ERC20 between to chains ```bash polycli ulxly bridge asset [flags] @@ -19,68 +19,76 @@ polycli ulxly bridge asset [flags] ## Usage -This command will attempt to send a deposit transaction to the bridge contract. +This command will directly attempt to make a deposit on the uLxLy bridge. This call responds to the method defined below: ```solidity - /** - * @notice Deposit add a new leaf to the merkle tree - * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call - * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. - * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens - * do not call any external address in that case - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amount Amount of tokens - * @param token Token address, 0 address is reserved for ether - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param permitData Raw data of the call `permit` of the token - */ - function bridgeAsset( - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - address token, - bool forceUpdateGlobalExitRoot, - bytes calldata permitData - ); - +/** + * @notice Deposit add a new leaf to the merkle tree + * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call + * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. + * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens + * do not call any external address in that case + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param token Token address, 0 address is reserved for ether + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param permitData Raw data of the call `permit` of the token + */ +function bridgeAsset( + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + address token, + bool forceUpdateGlobalExitRoot, + bytes calldata permitData +) public payable virtual ifNotEmergencyState nonReentrant { ``` -Each transaction will require manual input of parameters. Example usage: +The source of this method is [here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L198-L219). +Below is an example of how we would make simple bridge of native ETH from Sepolia (L1) into Cardona (L2). ```bash -polycli ulxly bridge-asset \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --gas-limit 300000 \ - --amount 1000000000000000000 \ - --rpc-url http://127.0.0.1:8545 \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --destination-network 1 \ - --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 +polycli ulxly bridge asset \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 1 \ + --value 10000000000000000 \ + --rpc-url https://sepolia.drpc.org ``` -This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: +[This](https://sepolia.etherscan.io/tx/0xf57b8171b2f62dce3eedbe3e50d5ee8413d61438af64286b5017ed9d5d154816) is the transaction that was created and mined from running this command. + +Here is another example that will bridge a [test ERC20 token](https://sepolia.etherscan.io/address/0xC92AeF5873d058a76685140F3328B0DED79733Af) from Sepolia (L1) into Cardona (L2). In order for this to work, the token would need to have an [approval](https://sepolia.etherscan.io/tx/0x028513b13a2a7899de4db56e60d1dad66c7b7e29f91c54f385fdfdfc8f14b8b4#eventlog) for the bridge to spend tokens for that particular user. ```bash -Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +polycli ulxly bridge asset \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 1 \ + --value 10000000000000000 \ + --token-address 0xC92AeF5873d058a76685140F3328B0DED79733Af \ + --destination-address 0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 \ + --rpc-url https://sepolia.drpc.org ``` -Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command +[This](https://sepolia.etherscan.io/tx/0x8ed1c2c0f2e994c86867f401c86fea3c709a28a18629d473cf683049f176fa93) is the transaction that was created and mined from running this command. - -Failed deposit transactions will output logs like below: +Assuming you have funds on L2, a bridge from L2 to L1 looks pretty much the same. +The command below will bridge `123456` of the native ETH on Cardona (L2) back to network 0 which corresponds to Sepolia (L1). ```bash -Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 -Try increasing the gas limit: -Current gas limit: 100000 -Cumulative gas used for transaction: 98641 +polycli ulxly bridge asset \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 0 \ + --value 123456 \ + --destination-address 0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 \ + --rpc-url https://rpc.cardona.zkevm-rpc.com ``` -The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. - +[This](https://cardona-zkevm.polygonscan.com/tx/0x0294dae3cfb26881e5dde9f182531aa5be0818956d029d50e9872543f020df2e) is the transaction that was created and mined from running this command. ## Flags ```bash @@ -118,4 +126,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly bridge](polycli_ulxly__bridge.md) - commands for making deposits to the uLxLy bridge +- [polycli ulxly bridge](polycli_ulxly__bridge.md) - Commands for moving funds and sending messages from one chain to another diff --git a/doc/polycli_ulxly__bridge_message.md b/doc/polycli_ulxly__bridge_message.md index 879946c38..16a8d63c1 100644 --- a/doc/polycli_ulxly__bridge_message.md +++ b/doc/polycli_ulxly__bridge_message.md @@ -11,7 +11,7 @@ ## Description -send some value along with call data into the bridge +Send some ETH along with data from one chain to another chain ```bash polycli ulxly bridge message [flags] @@ -19,59 +19,72 @@ polycli ulxly bridge message [flags] ## Usage -This command will attempt to send a deposit transaction to the bridge contract. +This command is very similar to `polycli ulxly bridge asset`, but instead this is a more generic interface that can be used to transfer ETH and make a contract call. This is the underlying solidity interface that we're referencing. ```solidity - /** - * @notice Bridge message and send ETH value - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param metadata Message metadata - */ - function bridgeMessage( - uint32 destinationNetwork, - address destinationAddress, - bool forceUpdateGlobalExitRoot, - bytes calldata metadata - ); +/** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ +function bridgeMessage( + uint32 destinationNetwork, + address destinationAddress, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata +) external payable ifNotEmergencyState { ``` -Each transaction will require manual input of parameters. Example usage: +The source code for this particular method is [here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L324-L337). + +Below is a simple example of using this command to bridge a small amount of ETH from Sepolia (L1) to Cardona (L2). In this case, we're not including any call data, so it's essentially equivalent to a `bridge asset` call, but the deposit will not be automatically claimed on L2. ```bash -polycli ulxly bridge-message \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --gas-limit 300000 \ - --amount 1000000000000000000 \ - --rpc-url http://127.0.0.1:8545 \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --destination-network 1 \ - --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 - --call-data 0x001010109200090028979743971976836486868648629808961824738090896826764980866fac97863898ca08928fc7279643 +polycli ulxly bridge message \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 1 \ + --value 10000000000000000 \ + --rpc-url https://sepolia.drpc.org ``` -This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: +[This](https://sepolia.etherscan.io/tx/0x1a6e2be69fa65e866889d95403b2fe820f08b6a07b96c6afbde646b8092addb2) is the transaction that was generated and mined from this command. +In most cases, you'll want to specify some `call-data` and a `destination-address` in order for a contract to be called on the destination chain. For example: ```bash -Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 +polycli ulxly bridge message \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-network 1 \ + --destination-address 0xC92AeF5873d058a76685140F3328B0DED79733Af \ + --call-data 0x40c10f190000000000000000000000003878cff9d621064d393eef92bf1e12a944c5ba84000000000000000000000000000000000000000000000000002386f26fc10000 \ + --value 0 \ + --rpc-url https://sepolia.drpc.org ``` +[This](https://sepolia.etherscan.io/tx/0x517b9d827a3a81770d608a6b997e230d992e1e0cabc0fd2797285693b1cc6a9f) is the transaction that was created and mined from running the above command. -Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command - +In this case, I've configured the destination address to be a test contract I've deployed on L2. +```soldity +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity 0.8.20; -Failed deposit transactions will output logs like below: +contract MessageEmitter { + event MessageReceived (address originAddress, uint32 originNetwork, bytes data); -```bash -Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 -Try increasing the gas limit: -Current gas limit: 100000 -Cumulative gas used for transaction: 98641 + function onMessageReceived(address originAddress, uint32 originNetwork, bytes memory data) external payable { + emit MessageReceived(originAddress, originNetwork, data); + } +} ``` -The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. +The idea is to have minimal contract that will meet the expected interface of the bridge contract: https://github.com/0xPolygonHermez/zkevm-contracts/blob/v9.0.0-rc.3-pp/contracts/interfaces/IBridgeMessageReceiver.sol + +In this case, I didn't bother implementing the proxy to an ERC20 or extending some ERC20 contract. I'm just emitting an event to know that the transaction actually fired as expected. +The calldata comes from running this command `cast calldata 'mint(address account, uint256 amount)' 0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 10000000000000000`. Again, in this case no ERC20 will be minted because I didn't set it up. + ## Flags @@ -110,4 +123,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly bridge](polycli_ulxly__bridge.md) - commands for making deposits to the uLxLy bridge +- [polycli ulxly bridge](polycli_ulxly__bridge.md) - Commands for moving funds and sending messages from one chain to another diff --git a/doc/polycli_ulxly__bridge_weth.md b/doc/polycli_ulxly__bridge_weth.md index 5eccf9570..d0011bb5e 100644 --- a/doc/polycli_ulxly__bridge_weth.md +++ b/doc/polycli_ulxly__bridge_weth.md @@ -11,7 +11,7 @@ ## Description -send some WETH into the bridge +For L2's that use a gas token, use this to transfer WETH to another chain ```bash polycli ulxly bridge weth [flags] @@ -19,61 +19,41 @@ polycli ulxly bridge weth [flags] ## Usage -This command will attempt to send a deposit transaction to the bridge contract. +This command is not used very often but can be used on L2 networks that have a gas token. ```solidity - /** - * @notice Bridge message and send ETH value - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amountWETH Amount of WETH tokens - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param metadata Message metadata - */ - function bridgeMessageWETH( - uint32 destinationNetwork, - address destinationAddress, - uint256 amountWETH, - bool forceUpdateGlobalExitRoot, - bytes calldata metadata - ); +/** + * @notice Bridge message and send ETH value + * note User/UI must be aware of the existing/available networks when choosing the destination network + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amountWETH Amount of WETH tokens + * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not + * @param metadata Message metadata + */ +function bridgeMessageWETH( + uint32 destinationNetwork, + address destinationAddress, + uint256 amountWETH, + bool forceUpdateGlobalExitRoot, + bytes calldata metadata +) external ifNotEmergencyState { ``` +[Here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L352-L367) is the source code that corresponds to this interface. -Each transaction will require manual input of parameters. Example usage: +Assuming the network is configured with a gas token, you could call this method like this: ```bash -polycli ulxly bridge-message-weth \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --gas-limit 300000 \ - --amount 1000000000000000000 \ - --rpc-url http://127.0.0.1:8545 \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ +polycli ulxly bridge weth \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --destination-address 0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --value 123456 \ --destination-network 1 \ - --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 - --call-data 0x001010109200090028979743971976836486868648629808961824738090896826764980866fac97863898ca08928fc7279643 + --rpc-url http://l2-rpc-url.invalid \ + --token-address $WETH_ADDRESS ``` -This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: - -```bash -Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 -``` - -Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command - - -Failed deposit transactions will output logs like below: - -```bash -Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 -Try increasing the gas limit: -Current gas limit: 100000 -Cumulative gas used for transaction: 98641 -``` - -The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. ## Flags @@ -112,4 +92,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly bridge](polycli_ulxly__bridge.md) - commands for making deposits to the uLxLy bridge +- [polycli ulxly bridge](polycli_ulxly__bridge.md) - Commands for moving funds and sending messages from one chain to another diff --git a/doc/polycli_ulxly__claim-everything.md b/doc/polycli_ulxly__claim-everything.md index 00e289a19..2659f5201 100644 --- a/doc/polycli_ulxly__claim-everything.md +++ b/doc/polycli_ulxly__claim-everything.md @@ -11,7 +11,7 @@ ## Description -attempt to claim any unclaimed deposits +Attempt to claim as many deposits and messages as possible ```bash polycli ulxly claim-everything [flags] diff --git a/doc/polycli_ulxly__claim.md b/doc/polycli_ulxly__claim.md index e38dd9fd0..50f45e52e 100644 --- a/doc/polycli_ulxly__claim.md +++ b/doc/polycli_ulxly__claim.md @@ -11,14 +11,14 @@ ## Description -commands for making claims of deposits from the uLxLy bridge +Commands for claiming deposits on a particular chain ## Flags ```bash --bridge-service-url string the URL of the bridge service --deposit-count uint the deposit count of the bridge transaction - --deposit-network uint the rollup id of the network where the bridge is being claimed + --deposit-network uint the rollup id of the network where the deposit was initially made --global-index string an override of the global index value -h, --help help for claim ``` @@ -50,7 +50,7 @@ The command also inherits flags from parent commands. ## See also - [polycli ulxly ](polycli_ulxly_.md) - -- [polycli ulxly claim asset](polycli_ulxly__claim_asset.md) - perform a claim of a given deposit in the bridge +- [polycli ulxly claim asset](polycli_ulxly__claim_asset.md) - Claim a deposit -- [polycli ulxly claim message](polycli_ulxly__claim_message.md) - perform a claim of a given message in the bridge +- [polycli ulxly claim message](polycli_ulxly__claim_message.md) - Claim a message diff --git a/doc/polycli_ulxly__claim_asset.md b/doc/polycli_ulxly__claim_asset.md index 13e209c70..ae7f25347 100644 --- a/doc/polycli_ulxly__claim_asset.md +++ b/doc/polycli_ulxly__claim_asset.md @@ -11,7 +11,7 @@ ## Description -perform a claim of a given deposit in the bridge +Claim a deposit ```bash polycli ulxly claim asset [flags] @@ -19,83 +19,86 @@ polycli ulxly claim asset [flags] ## Usage -This command will attempt to send a claim transaction to the bridge contract. +This command will connect to the bridge service, generate a proof, and then attempt to claim the deposit on which never network is referred to in the `--rpc-url` argument. +This is the corresponding interface in the bridge contract: ```solidity - /** - * @notice Verify merkle proof and withdraw tokens/ether - * @param smtProofLocalExitRoot Smt proof to proof the leaf against the network exit root - * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root - * @param globalIndex Global index is defined as: - * | 191 bits | 1 bit | 32 bits | 32 bits | - * | 0 | mainnetFlag | rollupIndex | localRootIndex | - * note that only the rollup index will be used only in case the mainnet flag is 0 - * note that global index do not assert the unused bits to 0. - * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract - * to avoid possible synch attacks - * @param mainnetExitRoot Mainnet exit root - * @param rollupExitRoot Rollup exit root - * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amount Amount of tokens - * @param metadata Abi encoded metadata if any, empty otherwise - */ - function claimAsset( - bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, - bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, - uint256 globalIndex, - bytes32 mainnetExitRoot, - bytes32 rollupExitRoot, - uint32 originNetwork, - address originTokenAddress, - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - bytes calldata metadata - ); - +/** + * @notice Verify merkle proof and withdraw tokens/ether + * @param smtProofLocalExitRoot Smt proof to proof the leaf against the network exit root + * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root + * @param globalIndex Global index is defined as: + * | 191 bits | 1 bit | 32 bits | 32 bits | + * | 0 | mainnetFlag | rollupIndex | localRootIndex | + * note that only the rollup index will be used only in case the mainnet flag is 0 + * note that global index do not assert the unused bits to 0. + * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract + * to avoid possible synch attacks + * @param mainnetExitRoot Mainnet exit root + * @param rollupExitRoot Rollup exit root + * @param originNetwork Origin network + * @param originTokenAddress Origin token address, 0 address is reserved for gas token address. If WETH address is zero, means this gas token is ether, else means is a custom erc20 gas token + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount Amount of tokens + * @param metadata Abi encoded metadata if any, empty otherwise + */ +function claimAsset( + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originTokenAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata +) external ifNotEmergencyState { ``` -Each transaction will require manual input of parameters. Example usage: +[Here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L433-L465) is a direct link to the source code as well. -```bash -polycli ulxly deposit-claim \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --claim-index 0 \ - --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ - --claim-network 0 \ - --rpc-url http://127.0.0.1:32790 \ - --bridge-service-url http://127.0.0.1:32804 -``` - -This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: +In order to claim an asset or a message, you need to know deposit count. Usually this is in the event data of the transaction. Alternatively, you can usually directly attempt to see the pending deposits by querying the bridge API directly. In the case of Cardona, the bridge service is running here: https://bridge-api.cardona.zkevm-rpc.com ```bash -Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b +curl -s https://bridge-api.cardona.zkevm-rpc.com/bridges/0x3878Cff9d621064d393EEF92bF1e12A944c5ba84 | jq '.' ``` -Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` - - -Failed deposit transactions will output logs like below: - -```bash -Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a +In the output of the above command, I can see a deposit that looks like this: +```json +{ + "leaf_type": 0, + "orig_net": 0, + "orig_addr": "0x0000000000000000000000000000000000000000", + "amount": "123456", + "dest_net": 0, + "dest_addr": "0x3878Cff9d621064d393EEF92bF1e12A944c5ba84", + "block_num": "9695587", + "deposit_cnt": 9075, + "network_id": 1, + "tx_hash": "0x0294dae3cfb26881e5dde9f182531aa5be0818956d029d50e9872543f020df2e", + "claim_tx_hash": "", + "metadata": "0x", + "ready_for_claim": true, + "global_index": "9075" +} ``` -The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: +If we want to claim this deposit, we can use a command like this: -```! -curl http://127.0.0.1:32790 \ --X POST \ --H "Content-Type: application/json" \ ---data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' +```bash +polycli ulxly claim asset \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --bridge-service-url https://bridge-api.cardona.zkevm-rpc.com \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --deposit-network 1 \ + --deposit-count 9075 \ + --rpc-url https://sepolia.drpc.org ``` +[Here](https://sepolia.etherscan.io/tx/0x21fee6e47a3b6733034fb963b20fe7accb0fb168257450f8f0053d6af8e4bc76) is the transaction that was created and mined based on this command. ## Flags ```bash @@ -110,7 +113,7 @@ The command also inherits flags from parent commands. --chain-id string set the chain id to be used in the transaction --config string config file (default is $HOME/.polygon-cli.yaml) --deposit-count uint the deposit count of the bridge transaction - --deposit-network uint the rollup id of the network where the bridge is being claimed + --deposit-network uint the rollup id of the network where the deposit was initially made --destination-address string the address where the bridge will be sent to --dry-run do all of the transaction steps but do not send the transaction --gas-limit uint force a gas limit when sending a transaction @@ -132,4 +135,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly claim](polycli_ulxly__claim.md) - commands for making claims of deposits from the uLxLy bridge +- [polycli ulxly claim](polycli_ulxly__claim.md) - Commands for claiming deposits on a particular chain diff --git a/doc/polycli_ulxly__claim_message.md b/doc/polycli_ulxly__claim_message.md index 582387c36..c41ccb21e 100644 --- a/doc/polycli_ulxly__claim_message.md +++ b/doc/polycli_ulxly__claim_message.md @@ -11,7 +11,7 @@ ## Description -perform a claim of a given message in the bridge +Claim a message ```bash polycli ulxly claim message [flags] @@ -19,63 +19,90 @@ polycli ulxly claim message [flags] ## Usage -This command will attempt to send a claim transaction to the bridge contract. +This command is used to claim a message type deposit. Here is the interface of the method that's being used: ```solidity - /** - * @notice Bridge message and send ETH value - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param metadata Message metadata - */ - function bridgeMessage( - uint32 destinationNetwork, - address destinationAddress, - bool forceUpdateGlobalExitRoot, - bytes calldata metadata - ); - +/** + * @notice Verify merkle proof and execute message + * If the receiving address is an EOA, the call will result as a success + * Which means that the amount of ether will be transferred correctly, but the message + * will not trigger any execution + * @param smtProofLocalExitRoot Smt proof to proof the leaf against the exit root + * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root + * @param globalIndex Global index is defined as: + * | 191 bits | 1 bit | 32 bits | 32 bits | + * | 0 | mainnetFlag | rollupIndex | localRootIndex | + * note that only the rollup index will be used only in case the mainnet flag is 0 + * note that global index do not assert the unused bits to 0. + * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract + * to avoid possible synch attacks + * @param mainnetExitRoot Mainnet exit root + * @param rollupExitRoot Rollup exit root + * @param originNetwork Origin network + * @param originAddress Origin address + * @param destinationNetwork Network destination + * @param destinationAddress Address destination + * @param amount message value + * @param metadata Abi encoded metadata if any, empty otherwise + */ +function claimMessage( + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata +) external ifNotEmergencyState { ``` -Each transaction will require manual input of parameters. Example usage: - -```bash -polycli ulxly deposit-claim \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --claim-index 0 \ - --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ - --claim-network 0 \ - --rpc-url http://127.0.0.1:32790 \ - --bridge-service-url http://127.0.0.1:32804 -``` +[Here](https://github.com/0xPolygonHermez/zkevm-contracts/blob/c8659e6282340de7bdb8fdbf7924a9bd2996bc98/contracts/v2/PolygonZkEVMBridgeV2.sol#L588-L623) is a link to the source code. -This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: +This command is essentially identical to `claim asset`, but it's specific to deposits that are of the message leaf type rather than assets. In order to use this command, I'm going to try to claim one of the messages that I sent while testing `polycli ulxly bridge message`. ```bash -Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b +curl -s https://bridge-api.cardona.zkevm-rpc.com/bridges/0xC92AeF5873d058a76685140F3328B0DED79733Af | jq '.' ``` -Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` - +This will show me the deposits that are destined for the test contract that I deployed on L2. At the moment here is the deposit I'm interested in: + +```json +{ + "leaf_type": 1, + "orig_net": 0, + "orig_addr": "0x3878Cff9d621064d393EEF92bF1e12A944c5ba84", + "amount": "0", + "dest_net": 1, + "dest_addr": "0xC92AeF5873d058a76685140F3328B0DED79733Af", + "block_num": "7435415", + "deposit_cnt": 67305, + "network_id": 0, + "tx_hash": "0x517b9d827a3a81770d608a6b997e230d992e1e0cabc0fd2797285693b1cc6a9f", + "claim_tx_hash": "", + "metadata": "0x40c10f190000000000000000000000003878cff9d621064d393eef92bf1e12a944c5ba84000000000000000000000000000000000000000000000000002386f26fc10000", + "ready_for_claim": true, + "global_index": "18446744073709618921" +} +``` -Failed deposit transactions will output logs like below: +I'm going to use this command to try to claim this message on L2. ```bash -Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a +polycli ulxly claim message \ + --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ + --bridge-service-url https://bridge-api.cardona.zkevm-rpc.com \ + --private-key 0x32430699cd4f46ab2422f1df4ad6546811be20c9725544e99253a887e971f92b \ + --destination-address 0xC92AeF5873d058a76685140F3328B0DED79733Af \ + --deposit-network 0 \ + --deposit-count 67305 \ + --rpc-url https://rpc.cardona.zkevm-rpc.com ``` -The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: - -```! -curl http://127.0.0.1:32790 \ --X POST \ --H "Content-Type: application/json" \ ---data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' -``` +[Here](https://cardona-zkevm.polygonscan.com/tx/0x6df4c4e43776d703bf1996334a4e1975bb3c124192563c93e3d199d9240dd56f#eventlog) is the transaction that was generated by this command. Everything looks to have worked properly. The `MessageReceived(address,uint32,bytes)` event with signature `0xe97c9b3f13b44bc13bde4743ae654dff72f8dc2ff9ff6070efc5999f77a37716` showed up in the explorer so our contract fired properly when the claim was made. ## Flags @@ -91,7 +118,7 @@ The command also inherits flags from parent commands. --chain-id string set the chain id to be used in the transaction --config string config file (default is $HOME/.polygon-cli.yaml) --deposit-count uint the deposit count of the bridge transaction - --deposit-network uint the rollup id of the network where the bridge is being claimed + --deposit-network uint the rollup id of the network where the deposit was initially made --destination-address string the address where the bridge will be sent to --dry-run do all of the transaction steps but do not send the transaction --gas-limit uint force a gas limit when sending a transaction @@ -113,4 +140,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly claim](polycli_ulxly__claim.md) - commands for making claims of deposits from the uLxLy bridge +- [polycli ulxly claim](polycli_ulxly__claim.md) - Commands for claiming deposits on a particular chain diff --git a/doc/polycli_ulxly_empty-proof.md b/doc/polycli_ulxly_empty-proof.md index 31e2dccc7..076c79e70 100644 --- a/doc/polycli_ulxly_empty-proof.md +++ b/doc/polycli_ulxly_empty-proof.md @@ -43,4 +43,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the lxly bridge +- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the uLxLy bridge diff --git a/doc/polycli_ulxly_get-deposits.md b/doc/polycli_ulxly_get-deposits.md index 8711e98db..4588799c1 100644 --- a/doc/polycli_ulxly_get-deposits.md +++ b/doc/polycli_ulxly_get-deposits.md @@ -94,4 +94,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the lxly bridge +- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the uLxLy bridge diff --git a/doc/polycli_ulxly_proof.md b/doc/polycli_ulxly_proof.md index 77eeba1b9..2056b770c 100644 --- a/doc/polycli_ulxly_proof.md +++ b/doc/polycli_ulxly_proof.md @@ -117,4 +117,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the lxly bridge +- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the uLxLy bridge diff --git a/doc/polycli_ulxly_zero-proof.md b/doc/polycli_ulxly_zero-proof.md index db4436241..aae86f579 100644 --- a/doc/polycli_ulxly_zero-proof.md +++ b/doc/polycli_ulxly_zero-proof.md @@ -48,4 +48,4 @@ The command also inherits flags from parent commands. ## See also -- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the lxly bridge +- [polycli ulxly](polycli_ulxly.md) - Utilities for interacting with the uLxLy bridge From 31e28d625dfb6c8d6784e18b8c92cb8c5579f387 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Thu, 9 Jan 2025 07:28:10 -0500 Subject: [PATCH 22/24] docs: updating --- cmd/ulxly/depositClaimUsage.md | 76 ------------------------------- cmd/ulxly/depositGetUsage.md | 8 ++-- cmd/ulxly/depositNewUsage.md | 61 ------------------------- cmd/ulxly/proofUsage.md | 15 +++--- doc/polycli_ulxly_get-deposits.md | 8 ++-- doc/polycli_ulxly_proof.md | 14 +++--- 6 files changed, 25 insertions(+), 157 deletions(-) delete mode 100644 cmd/ulxly/depositClaimUsage.md delete mode 100644 cmd/ulxly/depositNewUsage.md diff --git a/cmd/ulxly/depositClaimUsage.md b/cmd/ulxly/depositClaimUsage.md deleted file mode 100644 index bfe1706c3..000000000 --- a/cmd/ulxly/depositClaimUsage.md +++ /dev/null @@ -1,76 +0,0 @@ -This command will attempt to send a claim transaction to the bridge contract. - -```solidity - /** - * @notice Verify merkle proof and withdraw tokens/ether - * @param smtProofLocalExitRoot Smt proof to proof the leaf against the network exit root - * @param smtProofRollupExitRoot Smt proof to proof the rollupLocalExitRoot against the rollups exit root - * @param globalIndex Global index is defined as: - * | 191 bits | 1 bit | 32 bits | 32 bits | - * | 0 | mainnetFlag | rollupIndex | localRootIndex | - * note that only the rollup index will be used only in case the mainnet flag is 0 - * note that global index do not assert the unused bits to 0. - * This means that when synching the events, the globalIndex must be decoded the same way that in the Smart contract - * to avoid possible synch attacks - * @param mainnetExitRoot Mainnet exit root - * @param rollupExitRoot Rollup exit root - * @param originNetwork Origin network - * @param originTokenAddress Origin token address, 0 address is reserved for ether - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amount Amount of tokens - * @param metadata Abi encoded metadata if any, empty otherwise - */ - function claimAsset( - bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, - bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, - uint256 globalIndex, - bytes32 mainnetExitRoot, - bytes32 rollupExitRoot, - uint32 originNetwork, - address originTokenAddress, - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - bytes calldata metadata - ) - -``` - -Each transaction will require manual input of parameters. Example usage: - -```bash -polycli ulxly deposit-claim \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --claim-index 0 \ - --claim-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 \ - --claim-network 0 \ - --rpc-url http://127.0.0.1:32790 \ - --bridge-service-url http://127.0.0.1:32804 -``` - -This command would use the supplied private key and attempt to send a claim transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: - -```bash -Claim Transaction Successful: 0x7180201b19e1aa596503d8541137d6f341e682835bf7a54aab6422c89158866b -``` - -Upon successful claim, the transferred funds can be queried in the destination network using tools like `cast balance --rpc-url ` - - -Failed deposit transactions will output logs like below: - -```bash -Claim Transaction Failed: 0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a -``` - -The reason for failing may be very difficult to debug. I have personally spun up a bridge-ui and compared the byte data of a successful transaction to the byte data of a failing claim transaction queried using: - -```! -curl http://127.0.0.1:32790 \ --X POST \ --H "Content-Type: application/json" \ ---data '{"method":"debug_traceTransaction","params":["0x32ac34797159c79e57ae801c350bccfe5f8105d4dd3b717e31d811397e98036a", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' | jq '.' -``` diff --git a/cmd/ulxly/depositGetUsage.md b/cmd/ulxly/depositGetUsage.md index 409467fbd..b1067f832 100644 --- a/cmd/ulxly/depositGetUsage.md +++ b/cmd/ulxly/depositGetUsage.md @@ -1,5 +1,5 @@ This command will attempt to scan a range of blocks and look for uLxLy -Bridge Events. This is is the specific signature that we're interested +Bridge Events. This is the specific signature that we're interested in: ```solidity @@ -27,7 +27,7 @@ Each event that we counter will be parsed and written as JSON to stdout. Example usage: ```bash -polycli ulxly deposit-get \ +polycli ulxly get-deposits \ --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ --rpc-url https://eth-sepolia.g.alchemy.com/v2/demo \ --from-block 4880876 \ @@ -35,12 +35,12 @@ polycli ulxly deposit-get \ --filter-size 9999 > cardona-4880876-to-6028159.ndjson ``` -This command would look for bridge events from block `4880876` to +This command will look for bridge events from block `4880876` to block `6028159` in increments of `9999` blocks at a time for the contract address `0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582`. The output will be written as newline delimited JSON. -This command is very specific for the ulxly bridge and it's meant to +This command is very specific for the ulxly bridge, and it's meant to serve as the input to the proof command. diff --git a/cmd/ulxly/depositNewUsage.md b/cmd/ulxly/depositNewUsage.md deleted file mode 100644 index de9d842ac..000000000 --- a/cmd/ulxly/depositNewUsage.md +++ /dev/null @@ -1,61 +0,0 @@ -This command will attempt to send a deposit transaction to the bridge contract. - -```solidity - /** - * @notice Deposit add a new leaf to the merkle tree - * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call - * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. - * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens - * do not call any external address in that case - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amount Amount of tokens - * @param token Token address, 0 address is reserved for ether - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param permitData Raw data of the call `permit` of the token - */ - function bridgeAsset( - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - address token, - bool forceUpdateGlobalExitRoot, - bytes calldata permitData - ); - -``` - -Each transaction will require manual input of parameters. Example usage: - -```bash -polycli ulxly deposit-new \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --gas-limit 300000 \ - --amount 1000000000000000000 \ - --rpc-url http://127.0.0.1:8545 \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --destination-network 1 \ - --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 -``` - -This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: - -```bash -Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 -``` - -Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command - - -Failed deposit transactions will output logs like below: - -```bash -Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 -Try increasing the gas limit: -Current gas limit: 100000 -Cumulative gas used for transaction: 98641 -``` - -The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. diff --git a/cmd/ulxly/proofUsage.md b/cmd/ulxly/proofUsage.md index 3b4935300..b832a2ddf 100644 --- a/cmd/ulxly/proofUsage.md +++ b/cmd/ulxly/proofUsage.md @@ -6,12 +6,12 @@ Example usage: ```bash polycli ulxly proof \ --file-name cardona-4880876-to-6028159.ndjson \ - --deposit-number 24386 | jq '.' + --deposit-count 24386 | jq '.' ``` In this case we are assuming we have a file `cardona-4880876-to-6028159.ndjson` that would have been generated -with a call to `polycli ulxly deposits`. The output will be the +with a call to `polycli ulxly get-deposits`. The output will be the sibling hashes necessary to prove inclusion of deposit `24386`. This is a real verifiable deposit if you'd like to sanity check: @@ -66,7 +66,10 @@ This is the proof response from polycli: ![Sample Tree](./tree-diagram.png) -When we're creating the proof here, we're essentially storing all of -the paths to the various leafs. When we want to generate a proof, we -essentially find the appropriate sibling node in the tree to prove -that the leaf is part of the given merkle root. +When we're creating the proof here, we're essentially storing the paths to the +various leafs. When we want to generate a proof, we find the appropriate sibling +node in the tree to prove that the leaf is part of the given merkle root. + +## Full example + +TODO \ No newline at end of file diff --git a/doc/polycli_ulxly_get-deposits.md b/doc/polycli_ulxly_get-deposits.md index 4588799c1..01cc0ae76 100644 --- a/doc/polycli_ulxly_get-deposits.md +++ b/doc/polycli_ulxly_get-deposits.md @@ -20,7 +20,7 @@ polycli ulxly get-deposits [flags] ## Usage This command will attempt to scan a range of blocks and look for uLxLy -Bridge Events. This is is the specific signature that we're interested +Bridge Events. This is the specific signature that we're interested in: ```solidity @@ -48,7 +48,7 @@ Each event that we counter will be parsed and written as JSON to stdout. Example usage: ```bash -polycli ulxly deposit-get \ +polycli ulxly get-deposits \ --bridge-address 0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582 \ --rpc-url https://eth-sepolia.g.alchemy.com/v2/demo \ --from-block 4880876 \ @@ -56,12 +56,12 @@ polycli ulxly deposit-get \ --filter-size 9999 > cardona-4880876-to-6028159.ndjson ``` -This command would look for bridge events from block `4880876` to +This command will look for bridge events from block `4880876` to block `6028159` in increments of `9999` blocks at a time for the contract address `0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582`. The output will be written as newline delimited JSON. -This command is very specific for the ulxly bridge and it's meant to +This command is very specific for the ulxly bridge, and it's meant to serve as the input to the proof command. diff --git a/doc/polycli_ulxly_proof.md b/doc/polycli_ulxly_proof.md index 2056b770c..c890e6c30 100644 --- a/doc/polycli_ulxly_proof.md +++ b/doc/polycli_ulxly_proof.md @@ -27,12 +27,12 @@ Example usage: ```bash polycli ulxly proof \ --file-name cardona-4880876-to-6028159.ndjson \ - --deposit-number 24386 | jq '.' + --deposit-count 24386 | jq '.' ``` In this case we are assuming we have a file `cardona-4880876-to-6028159.ndjson` that would have been generated -with a call to `polycli ulxly deposits`. The output will be the +with a call to `polycli ulxly get-deposits`. The output will be the sibling hashes necessary to prove inclusion of deposit `24386`. This is a real verifiable deposit if you'd like to sanity check: @@ -87,11 +87,13 @@ This is the proof response from polycli: ![Sample Tree](./tree-diagram.png) -When we're creating the proof here, we're essentially storing all of -the paths to the various leafs. When we want to generate a proof, we -essentially find the appropriate sibling node in the tree to prove -that the leaf is part of the given merkle root. +When we're creating the proof here, we're essentially storing the paths to the +various leafs. When we want to generate a proof, we find the appropriate sibling +node in the tree to prove that the leaf is part of the given merkle root. +## Full example + +TODO ## Flags ```bash From f9aa81c87131cecadc35afa20bbeb74e9d52502a Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Thu, 9 Jan 2025 07:31:50 -0500 Subject: [PATCH 23/24] docs: removing old file --- cmd/ulxly/delete.md | 70 --------------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 cmd/ulxly/delete.md diff --git a/cmd/ulxly/delete.md b/cmd/ulxly/delete.md deleted file mode 100644 index 7c9c96e99..000000000 --- a/cmd/ulxly/delete.md +++ /dev/null @@ -1,70 +0,0 @@ -This command will attempt to send a deposit transaction to the bridge contract. - -```solidity - /** - * @notice Deposit add a new leaf to the merkle tree - * note If this function is called with a reentrant token, it would be possible to `claimTokens` in the same call - * Reducing the supply of tokens on this contract, and actually locking tokens in the contract. - * Therefore we recommend to third parties bridges that if they do implement reentrant call of `beforeTransfer` of some reentrant tokens - * do not call any external address in that case - * note User/UI must be aware of the existing/available networks when choosing the destination network - * @param destinationNetwork Network destination - * @param destinationAddress Address destination - * @param amount Amount of tokens - * @param token Token address, 0 address is reserved for ether - * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not - * @param permitData Raw data of the call `permit` of the token - */ - function bridgeAsset( - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - address token, - bool forceUpdateGlobalExitRoot, - bytes calldata permitData - ); - -``` - -Each transaction will require manual input of parameters. Example usage: - -```bash -polycli ulxly deposit-new \ - --private-key 12d7de8621a77640c9241b2595ba78ce443d05e94090365ab3bb5e19df82c625 \ - --gas-limit 300000 \ - --amount 1000000000000000000 \ - --rpc-url http://127.0.0.1:8545 \ - --bridge-address 0xD71f8F956AD979Cc2988381B8A743a2fE280537D \ - --destination-network 1 \ - --destination-address 0xE34aaF64b29273B7D567FCFc40544c014EEe9970 -``` -go run ulxly.go ulxly bridge-asset --private-key 846f556e5509c36b5756fa3741009310908d606db18d5916d43e6c7d22e0f5a7 --gas-limit 300000 --rpc-url https://sepolia.infura.io/v3/7c490aa772fa466293ee1ac62761330a --bridge-address 0x1348947e282138d8f377b467f7d9c2eb0f335d1f --destination-network 1 --amount 19 - -go run main.go ulxly bridge-message --private-key 846f556e5509c36b5756fa3741009310908d606db18d5916d43e6c7d22e0f5a7 --gas-limit 300000 --rpc-url https://sepolia.infura.io/v3/7c490aa772fa466293ee1ac62761330a --bridge-address 0x1348947e282138d8f377b467f7d9c2eb0f335d1f --destination-network 1 --amount 19 --call-data 0x18976546789087654356789654345678976543567897654356789765435468797865435468797654354678907654356879765436798765435467986543 - -go run main.go ulxly claim-asset --private-key 846f556e5509c36b5756fa3741009310908d606db18d5916d43e6c7d22e0f5a7 --gas-limit 30000000 --rpc-url https://sepolia.infura.io/v3/7c490aa772fa466293ee1ac62761330a --bridge-address 0x1348947e282138d8f377b467f7d9c2eb0f335d1f --claim-address 0x2536C2745Ac4A584656A830f7bdCd329c94e8F30 --claim-index 7780 --bridge-service-url https://bridge-api.internal.zkevm-rpc.com --deposit-network 1 - -go run main.go ulxly claim-message --private-key 846f556e5509c36b5756fa3741009310908d606db18d5916d43e6c7d -22e0f5a7 --gas-limit 300000 --rpc-url https://sepolia.infura.io/v3/7c490aa772fa466293ee1ac62761330a --bridge-address 0x1348947e282138d8f377b467f7d9c2eb0f335d1f --claim-address 0x2536C2745Ac4A584656A830f7bdCd329c94e8F30 --claim-index 7780 --call-data 0x18976546789087654356789654345678976543567897654356789765435468797865435468797654354678907654356879765436798765435467986543 --bridge-service-url https://bridge-api.internal.zkevm-rpc.com - - -This command would use the supplied private key and attempt to send a deposit transaction to the bridge contract address with the input flags. -Successful deposit transaction will output logs like below: - -```bash -Deposit Transaction Successful: 0x8c9b82e8abdfb4aad5fccd91879397acfa73e4261282c8dc634734d05ad889d3 -``` - -Upon successful deposit, the transaction can be queried using `polycli ulxly deposit-get` command - - -Failed deposit transactions will output logs like below: - -```bash -Deposit Transaction Failed: 0x60385209b0e9db359c24c88c2fb8a5c9e4628fffe8d5fb2b5e64dfac3a2b7639 -Try increasing the gas limit: -Current gas limit: 100000 -Cumulative gas used for transaction: 98641 -``` - -The reason for failing may likely be due to the `out of gas` error. Increasing the `--gas-limit` flag value will likely resolve this. From 3668496e1922f36035ff5f00e03d9cbc264e50e5 Mon Sep 17 00:00:00 2001 From: John Hilliard Date: Thu, 9 Jan 2025 07:35:58 -0500 Subject: [PATCH 24/24] docs: minor review changes --- cmd/ulxly/ulxly.go | 14 +++++++------- doc/polycli_ulxly.md | 4 ++-- doc/polycli_ulxly_get-deposits.md | 2 +- doc/polycli_ulxly_proof.md | 2 +- doc/polycli_ulxly_zero-proof.md | 10 +++++----- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index cee25a090..5d6f82817 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -1359,18 +1359,18 @@ func init() { Use: "zero-proof", Short: "create a proof that's filled with zeros", Long: `Use this command to print a proof response that's filled with the zero - hashes. This values are very helpful for debugging because it would - tell you how populated the tree is and roughly which leaves and - siblings are empty. It's also helpful for sanity checking a proof - response to understand if the hashed value is part of the zero hashes - or if it's actually an intermediate hash.`, +hashes. This values are very helpful for debugging because it would +tell you how populated the tree is and roughly which leaves and +siblings are empty. It's also helpful for sanity checking a proof +response to understand if the hashed value is part of the zero hashes +or if it's actually an intermediate hash.`, RunE: func(cmd *cobra.Command, args []string) error { return zeroProof() }, } proofCommand = &cobra.Command{ Use: "proof", - Short: "generate a proof for a given range of deposits", + Short: "Generate a proof for a given range of deposits", Long: proofUsage, RunE: func(cmd *cobra.Command, args []string) error { return proof(args) @@ -1378,7 +1378,7 @@ func init() { } getDepositCommand = &cobra.Command{ Use: "get-deposits", - Short: "generate ndjson for each bridge deposit over a particular range of blocks", + Short: "Generate ndjson for each bridge deposit over a particular range of blocks", Long: depositGetUsage, RunE: func(cmd *cobra.Command, args []string) error { return readDeposit(cmd) diff --git a/doc/polycli_ulxly.md b/doc/polycli_ulxly.md index 89e265d1a..4bd59e720 100644 --- a/doc/polycli_ulxly.md +++ b/doc/polycli_ulxly.md @@ -48,9 +48,9 @@ The command also inherits flags from parent commands. - [polycli ulxly empty-proof](polycli_ulxly_empty-proof.md) - create an empty proof -- [polycli ulxly get-deposits](polycli_ulxly_get-deposits.md) - generate ndjson for each bridge deposit over a particular range of blocks +- [polycli ulxly get-deposits](polycli_ulxly_get-deposits.md) - Generate ndjson for each bridge deposit over a particular range of blocks -- [polycli ulxly proof](polycli_ulxly_proof.md) - generate a proof for a given range of deposits +- [polycli ulxly proof](polycli_ulxly_proof.md) - Generate a proof for a given range of deposits - [polycli ulxly zero-proof](polycli_ulxly_zero-proof.md) - create a proof that's filled with zeros diff --git a/doc/polycli_ulxly_get-deposits.md b/doc/polycli_ulxly_get-deposits.md index 01cc0ae76..75e445b77 100644 --- a/doc/polycli_ulxly_get-deposits.md +++ b/doc/polycli_ulxly_get-deposits.md @@ -11,7 +11,7 @@ ## Description -generate ndjson for each bridge deposit over a particular range of blocks +Generate ndjson for each bridge deposit over a particular range of blocks ```bash polycli ulxly get-deposits [flags] diff --git a/doc/polycli_ulxly_proof.md b/doc/polycli_ulxly_proof.md index c890e6c30..6fca50e82 100644 --- a/doc/polycli_ulxly_proof.md +++ b/doc/polycli_ulxly_proof.md @@ -11,7 +11,7 @@ ## Description -generate a proof for a given range of deposits +Generate a proof for a given range of deposits ```bash polycli ulxly proof [flags] diff --git a/doc/polycli_ulxly_zero-proof.md b/doc/polycli_ulxly_zero-proof.md index aae86f579..c2f63ed39 100644 --- a/doc/polycli_ulxly_zero-proof.md +++ b/doc/polycli_ulxly_zero-proof.md @@ -20,11 +20,11 @@ polycli ulxly zero-proof [flags] ## Usage Use this command to print a proof response that's filled with the zero - hashes. This values are very helpful for debugging because it would - tell you how populated the tree is and roughly which leaves and - siblings are empty. It's also helpful for sanity checking a proof - response to understand if the hashed value is part of the zero hashes - or if it's actually an intermediate hash. +hashes. This values are very helpful for debugging because it would +tell you how populated the tree is and roughly which leaves and +siblings are empty. It's also helpful for sanity checking a proof +response to understand if the hashed value is part of the zero hashes +or if it's actually an intermediate hash. ## Flags ```bash