diff --git a/README.md b/README.md index 5601ca53..35f8bf6b 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,8 @@ Note: Do not modify this section! It is auto-generated by `cobra` using `make ge - [polycli wallet](doc/polycli_wallet.md) - Create or inspect BIP39(ish) wallets. +- [polycli wrap-contract](doc/polycli_wrap-contract.md) - Wrap deployed bytecode into create bytecode. + ## Testing diff --git a/cmd/retest/retest.go b/cmd/retest/retest.go index d7c452d2..73b1a94f 100644 --- a/cmd/retest/retest.go +++ b/cmd/retest/retest.go @@ -11,6 +11,7 @@ import ( "github.com/0xPolygon/polygon-cli/abi" "github.com/rs/zerolog/log" "github.com/spf13/cobra" + "github.com/0xPolygon/polygon-cli/util" "io" "math" "math/big" @@ -657,26 +658,11 @@ func processRawStringToString(data string) string { func WrapPredeployedCode(pre EthTestPre) string { rawCode := WrappedData{raw: pre.Code} deployedCode := rawCode.ToString() - deployedCode = strings.TrimPrefix(deployedCode, "0x") storageInitCode := storageToByteCode(pre.Storage) - codeCopySize := len(deployedCode) / 2 - codeCopyOffset := (len(storageInitCode) / 2) + 13 + 8 // 13 for CODECOPY + 8 for RETURN - - return fmt.Sprintf( - "0x%s"+ // storage initialization code - "63%08x"+ // PUSH4 to indicate the size of the data that should be copied into memory - "63%08x"+ // PUSH4 to indicate the offset in the call data to start the copy - "6000"+ // PUSH1 00 to indicate the destination offset in memory - "39"+ // CODECOPY - "63%08x"+ // PUSH4 to indicate the size of the data to be returned from memory - "6000"+ // PUSH1 00 to indicate that it starts from offset 0 - "F3"+ // RETURN - "%s", // CODE starts here. - storageInitCode, codeCopySize, codeCopyOffset, codeCopySize, deployedCode) + return util.WrapDeployedCode(deployedCode, storageInitCode) } - // storageToByteCode func storageToByteCode(storage map[string]EthTestNumeric) string { if len(storage) == 0 { diff --git a/cmd/root.go b/cmd/root.go index e4240f26..4b794202 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -30,6 +30,7 @@ import ( "github.com/0xPolygon/polygon-cli/cmd/signer" "github.com/0xPolygon/polygon-cli/cmd/version" "github.com/0xPolygon/polygon-cli/cmd/wallet" + "github.com/0xPolygon/polygon-cli/cmd/wrapcontract" ) var ( @@ -128,6 +129,7 @@ func NewPolycliCommand() *cobra.Command { ulxly.ULxLyCmd, version.VersionCmd, wallet.WalletCmd, + wrapcontract.WrapContractCmd, ) return cmd } diff --git a/cmd/wrapcontract/usage.md b/cmd/wrapcontract/usage.md new file mode 100644 index 00000000..789dd74c --- /dev/null +++ b/cmd/wrapcontract/usage.md @@ -0,0 +1,18 @@ +This command takes the runtime bytecode, the bytecode deployed on-chain, as input and converts it into creation bytecode, the bytecode used to create the contract + +```bash +$ polycli wrap-contract 69602a60005260206000f3600052600a6016f3 + +``` + +The resulting bytecode will be formatted this way: + + 0x?? // storage initialization code if any + 63?? // PUSH4 to indicate the size of the data that should be copied into memory + 63?? // PUSH4 to indicate the offset in the call data to start the copy + 6000 // PUSH1 00 to indicate the destination offset in memory + 39 // CODECOPY + 63?? // PUSH4 to indicate the size of the data to be returned from memory + 6000 // PUSH1 00 to indicate that it starts from offset 0 + F3 // RETURN + ??, // Deployed Bytecode diff --git a/cmd/wrapcontract/wrapcontract.go b/cmd/wrapcontract/wrapcontract.go new file mode 100644 index 00000000..101ea25b --- /dev/null +++ b/cmd/wrapcontract/wrapcontract.go @@ -0,0 +1,33 @@ +package wrapcontract + +import ( + "fmt" + _ "embed" + "github.com/spf13/cobra" + "github.com/0xPolygon/polygon-cli/util" +) + +var ( + //go:embed usage.md + usage string +) + +var WrapContractCmd = &cobra.Command{ + Use: "wrap-contract bytecode", + Aliases: []string{"wrapcontract", "wrapContract"}, + Short: "Wrap deployed bytecode into create bytecode.", + Long: usage, + RunE: func(cmd *cobra.Command, args []string) error { + deployed_bytecode := args[0] + storage_bytecode := "" + create_bytecode := util.WrapDeployedCode(deployed_bytecode, storage_bytecode) + fmt.Println(create_bytecode) + return nil + }, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return fmt.Errorf("expected exactly one argument: bytecode") + } + return nil + }, +} diff --git a/doc/polycli.md b/doc/polycli.md index c8d69f34..b0b91213 100644 --- a/doc/polycli.md +++ b/doc/polycli.md @@ -77,3 +77,5 @@ Polycli is a collection of tools that are meant to be useful while building, tes - [polycli wallet](polycli_wallet.md) - Create or inspect BIP39(ish) wallets. +- [polycli wrap-contract](polycli_wrap-contract.md) - Wrap deployed bytecode into create bytecode. + diff --git a/doc/polycli_wrap-contract.md b/doc/polycli_wrap-contract.md new file mode 100644 index 00000000..e67bae1e --- /dev/null +++ b/doc/polycli_wrap-contract.md @@ -0,0 +1,64 @@ +# `polycli wrap-contract` + +> Auto-generated documentation. + +## Table of Contents + +- [Description](#description) +- [Usage](#usage) +- [Flags](#flags) +- [See Also](#see-also) + +## Description + +Wrap deployed bytecode into create bytecode. + +```bash +polycli wrap-contract bytecode [flags] +``` + +## Usage + +This command takes the runtime bytecode, the bytecode deployed on-chain, as input and converts it into creation bytecode, the bytecode used to create the contract + +```bash +$ polycli wrap-contract 69602a60005260206000f3600052600a6016f3 + +``` + +The resulting bytecode will be formatted this way: + + 0x?? // storage initialization code if any + 63?? // PUSH4 to indicate the size of the data that should be copied into memory + 63?? // PUSH4 to indicate the offset in the call data to start the copy + 6000 // PUSH1 00 to indicate the destination offset in memory + 39 // CODECOPY + 63?? // PUSH4 to indicate the size of the data to be returned from memory + 6000 // PUSH1 00 to indicate that it starts from offset 0 + F3 // RETURN + ??, // Deployed Bytecode + +## Flags + +```bash + -h, --help help for wrap-contract +``` + +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](polycli.md) - A Swiss Army knife of blockchain tools. diff --git a/util/util.go b/util/util.go index a6f533ac..0c0fa159 100644 --- a/util/util.go +++ b/util/util.go @@ -317,3 +317,23 @@ func BlockUntilSuccessful(ctx context.Context, c *ethclient.Client, retryable fu b := backoff.WithContext(backoff.WithMaxRetries(backoff.NewConstantBackOff(5*time.Second), 24), ctx) return backoff.Retry(retryable, b) } + +func WrapDeployedCode(deployedBytecode string, storageBytecode string) string { + deployedBytecode = strings.ToLower(strings.TrimPrefix(deployedBytecode, "0x")) + storageBytecode = strings.ToLower(strings.TrimPrefix(storageBytecode, "0x")) + + codeCopySize := len(deployedBytecode) / 2 + codeCopyOffset := (len(storageBytecode)/2) + 13 + 8 // 13 for CODECOPY + 8 for RETURN + + return fmt.Sprintf( + "0x%s"+ // storage initialization code + "63%08x"+ // PUSH4 to indicate the size of the data that should be copied into memory + "63%08x"+ // PUSH4 to indicate the offset in the call data to start the copy + "6000"+ // PUSH1 00 to indicate the destination offset in memory + "39"+ // CODECOPY + "63%08x"+ // PUSH4 to indicate the size of the data to be returned from memory + "6000"+ // PUSH1 00 to indicate that it starts from offset 0 + "f3"+ // RETURN + "%s", // CODE starts here. + storageBytecode, codeCopySize, codeCopyOffset, codeCopySize, deployedBytecode) +}