Skip to content

Commit 197e752

Browse files
Merge pull request #455 from 0xPolygon/cmd/wrapcontract
Add storage initialization + read bytecode from file to wrap-contract
2 parents 66dc357 + bdc18d9 commit 197e752

File tree

5 files changed

+133
-34
lines changed

5 files changed

+133
-34
lines changed

cmd/retest/retest.go

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ func EthTestDataToString(data EthTestData) string {
330330
case reflect.Float64:
331331
// We have few tests with numeric code, ex:
332332
// "code": 16449,
333-
return processStorageData(data.(float64))
333+
return util.GetHexString(data.(float64))
334334

335335
default:
336336
log.Fatal().Any("input", data).Str("kind", v.Kind().String()).Msg("Attempted to convert unknown type to raw data")
@@ -378,25 +378,6 @@ func processTestDataString(data string) string {
378378
return ""
379379
}
380380

381-
func processStorageData(data any) string {
382-
var result string
383-
if reflect.TypeOf(data).Kind() == reflect.Float64 {
384-
result = fmt.Sprintf("%x", int64(data.(float64)))
385-
} else if reflect.TypeOf(data).Kind() == reflect.String {
386-
if strings.HasPrefix(data.(string), "0x") {
387-
result = strings.TrimPrefix(data.(string), "0x")
388-
} else {
389-
result = data.(string)
390-
}
391-
} else {
392-
log.Fatal().Any("data", data).Msg("unknown storage data type")
393-
}
394-
if len(result) % 2 != 0 {
395-
result = "0" + result
396-
}
397-
return result
398-
}
399-
400381
// isStandardSolidityString will do a rough check to see if the string looks like a typical solidity file rather than
401382
// the contracts that are usually in the retest code base
402383
func isStandardSolidityString(contract string) bool {
@@ -676,8 +657,8 @@ func storageToByteCode(storage map[string]EthTestNumeric) string {
676657
log.Warn().Str("slot", slot).Msg("found a storage entry for invalid slot")
677658
}
678659

679-
s := processStorageData(slot)
680-
v := processStorageData(value)
660+
s := util.GetHexString(slot)
661+
v := util.GetHexString(value)
681662
sLen := len(s) / 2
682663
vLen := len(v) / 2
683664
sPushCode := 0x5F + sLen

cmd/wrapcontract/usage.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,26 @@ This command takes the runtime bytecode, the bytecode deployed on-chain, as inpu
22

33
```bash
44
$ polycli wrap-contract 69602a60005260206000f3600052600a6016f3
5+
$ echo 69602a60005260206000f3600052600a6016f3 | polycli wrap-contract
56

67
```
78

9+
You can also provide a path to a file, and the bytecode while be read from there.
10+
11+
```bash
12+
$ polycli wrap-contract bytecode.txt
13+
$ polycli wrap-contract ../bytecode.txt
14+
$ polycli wrap-contract /tmp/bytecode.txt
15+
$ echo /tmp/bytecode.txt | polycli wrap-contract
16+
```
17+
18+
Additionally, you can provide storage for the contract in JSON
19+
```bash
20+
$ polycli wrap-contract 0x4455 --storage '{"0x01":"0x0034"}'
21+
$ polycli wrap-contract 0x4455 --storage '{"0x01":"0x0034", "0x02": "0xFF"}'
22+
$ echo 69602a60005260206000f3600052600a6016f3 | polycli wrap-contract --storage '{"0x01":"0x0034", "0x02": "0xFF"}'
23+
```
24+
825
The resulting bytecode will be formatted this way:
926

1027
0x?? // storage initialization code if any

cmd/wrapcontract/wrapcontract.go

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,96 @@
11
package wrapcontract
22

33
import (
4-
"fmt"
54
_ "embed"
6-
"github.com/spf13/cobra"
5+
"fmt"
6+
"io"
7+
"os"
8+
"strings"
9+
"encoding/json"
10+
711
"github.com/0xPolygon/polygon-cli/util"
12+
"github.com/spf13/cobra"
813
)
914

1015
var (
1116
//go:embed usage.md
12-
usage string
17+
usage string
18+
jsonStorage *string
1319
)
1420

1521
var WrapContractCmd = &cobra.Command{
16-
Use: "wrap-contract bytecode",
22+
Use: "wrap-contract bytecode|file",
1723
Aliases: []string{"wrapcontract", "wrapContract"},
1824
Short: "Wrap deployed bytecode into create bytecode.",
1925
Long: usage,
2026
RunE: func(cmd *cobra.Command, args []string) error {
21-
deployed_bytecode := args[0]
22-
storage_bytecode := ""
23-
create_bytecode := util.WrapDeployedCode(deployed_bytecode, storage_bytecode)
24-
fmt.Println(create_bytecode)
27+
deployedBytecode, err := getInputData(args)
28+
if err != nil {
29+
cmd.PrintErrf("There was an error reading input for wrapping contract: %s", err.Error())
30+
return err
31+
}
32+
storageBytecode, err := getStorageBytecode()
33+
if err != nil {
34+
cmd.PrintErrf("There was an error reading storage map: %s", err.Error())
35+
}
36+
createBytecode := util.WrapDeployedCode(deployedBytecode, storageBytecode)
37+
fmt.Println(createBytecode)
2538
return nil
2639
},
2740
Args: func(cmd *cobra.Command, args []string) error {
28-
if len(args) != 1 {
29-
return fmt.Errorf("expected exactly one argument: bytecode")
41+
if len(args) > 1 {
42+
return fmt.Errorf("expected at most one argument: bytecode")
3043
}
3144
return nil
3245
},
3346
}
47+
48+
func init() {
49+
flagSet := WrapContractCmd.PersistentFlags()
50+
jsonStorage = flagSet.String("storage", "", "Provide storage slots in json format k:v")
51+
}
52+
53+
func getInputData(args []string) (string, error) {
54+
var deployedBytecode string
55+
if len(args) == 0 {
56+
deployedBytecodeBytes, err := io.ReadAll(os.Stdin)
57+
if err != nil {
58+
return "", err
59+
}
60+
deployedBytecode = string(deployedBytecodeBytes)
61+
} else {
62+
deployedBytecodeOrFile := args[0]
63+
// Try to open the param as a file, otherwise treat it as bytecode
64+
deployedBytecodeBytes, err := os.ReadFile(deployedBytecodeOrFile)
65+
if err != nil {
66+
deployedBytecode = deployedBytecodeOrFile
67+
} else {
68+
deployedBytecode = string(deployedBytecodeBytes)
69+
}
70+
}
71+
72+
return strings.TrimSpace(deployedBytecode), nil
73+
}
74+
75+
func getStorageBytecode() (string, error) {
76+
var storageBytecode string = ""
77+
78+
if jsonStorage != nil && *jsonStorage != "" {
79+
var storage map[string]string
80+
err := json.Unmarshal([]byte(*jsonStorage), &storage)
81+
if err != nil {
82+
return storageBytecode, err
83+
}
84+
for k, v := range storage {
85+
slot := util.GetHexString(k)
86+
value := util.GetHexString(v)
87+
sLen := len(slot) / 2
88+
vLen := len(value) / 2
89+
sPushCode := 0x5f + sLen
90+
vPushCode := 0x5f + vLen
91+
storageBytecode += fmt.Sprintf("%02x%s%02x%s55", vPushCode, value, sPushCode, slot)
92+
}
93+
}
94+
95+
return storageBytecode, nil
96+
}

doc/polycli_wrap-contract.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
Wrap deployed bytecode into create bytecode.
1515

1616
```bash
17-
polycli wrap-contract bytecode [flags]
17+
polycli wrap-contract bytecode|file [flags]
1818
```
1919

2020
## Usage
@@ -23,9 +23,26 @@ This command takes the runtime bytecode, the bytecode deployed on-chain, as inpu
2323

2424
```bash
2525
$ polycli wrap-contract 69602a60005260206000f3600052600a6016f3
26+
$ echo 69602a60005260206000f3600052600a6016f3 | polycli wrap-contract
2627

2728
```
2829

30+
You can also provide a path to a file, and the bytecode while be read from there.
31+
32+
```bash
33+
$ polycli wrap-contract bytecode.txt
34+
$ polycli wrap-contract ../bytecode.txt
35+
$ polycli wrap-contract /tmp/bytecode.txt
36+
$ echo /tmp/bytecode.txt | polycli wrap-contract
37+
```
38+
39+
Additionally, you can provide storage for the contract in JSON
40+
```bash
41+
$ polycli wrap-contract 0x4455 --storage '{"0x01":"0x0034"}'
42+
$ polycli wrap-contract 0x4455 --storage '{"0x01":"0x0034", "0x02": "0xFF"}'
43+
$ echo 69602a60005260206000f3600052600a6016f3 | polycli wrap-contract --storage '{"0x01":"0x0034", "0x02": "0xFF"}'
44+
```
45+
2946
The resulting bytecode will be formatted this way:
3047

3148
0x?? // storage initialization code if any
@@ -41,7 +58,8 @@ The resulting bytecode will be formatted this way:
4158
## Flags
4259

4360
```bash
44-
-h, --help help for wrap-contract
61+
-h, --help help for wrap-contract
62+
--storage string Provide storage slots in json format k:v
4563
```
4664

4765
The command also inherits flags from parent commands.

util/util.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strconv"
88
"strings"
99
"time"
10+
"reflect"
1011

1112
"github.com/cenkalti/backoff"
1213
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -337,3 +338,22 @@ func WrapDeployedCode(deployedBytecode string, storageBytecode string) string {
337338
"%s", // CODE starts here.
338339
storageBytecode, codeCopySize, codeCopyOffset, codeCopySize, deployedBytecode)
339340
}
341+
342+
func GetHexString(data any) string {
343+
var result string
344+
if reflect.TypeOf(data).Kind() == reflect.Float64 {
345+
result = fmt.Sprintf("%x", int64(data.(float64)))
346+
} else if reflect.TypeOf(data).Kind() == reflect.String {
347+
if strings.HasPrefix(data.(string), "0x") {
348+
result = strings.TrimPrefix(data.(string), "0x")
349+
} else {
350+
result = data.(string)
351+
}
352+
} else {
353+
log.Fatal().Any("data", data).Msg("unknown storage data type")
354+
}
355+
if len(result) % 2 != 0 {
356+
result = "0" + result
357+
}
358+
return strings.ToLower(result)
359+
}

0 commit comments

Comments
 (0)