Skip to content

Commit

Permalink
override gas limit
Browse files Browse the repository at this point in the history
updates
  • Loading branch information
andrewkmin committed May 13, 2022
1 parent 1e0d913 commit d734dda
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 15 deletions.
8 changes: 4 additions & 4 deletions services/construction/construction_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func TestConstructionFlowWithPendingNonce(t *testing.T) {

// Test Metadata
metadata := &metadata{
GasLimit: big.NewInt(21000),
GasLimit: 21000,
GasPrice: big.NewInt(1000000000),
Nonce: 0,
To: "0x57B414a0332B5CaB885a451c2a28a07d1e9b8a8d",
Expand Down Expand Up @@ -202,7 +202,7 @@ func TestConstructionFlowWithPendingNonce(t *testing.T) {
parseMetadata := &parseMetadata{
Nonce: metadata.Nonce,
GasPrice: metadata.GasPrice,
GasLimit: metadata.GasLimit.Uint64(),
GasLimit: metadata.GasLimit,
ChainID: big.NewInt(80001),
}
assert.Equal(t, &types.ConstructionParseResponse{
Expand Down Expand Up @@ -332,7 +332,7 @@ func TestConstructionFlowWithInputNonce(t *testing.T) {

// Test Metadata
metadata := &metadata{
GasLimit: big.NewInt(21000),
GasLimit: 21000,
GasPrice: big.NewInt(1000000000),
Nonce: 1,
To: "0x57B414a0332B5CaB885a451c2a28a07d1e9b8a8d",
Expand Down Expand Up @@ -393,7 +393,7 @@ func TestConstructionFlowWithInputNonce(t *testing.T) {
parseMetadata := &parseMetadata{
Nonce: metadata.Nonce,
GasPrice: metadata.GasPrice,
GasLimit: metadata.GasLimit.Uint64(),
GasLimit: metadata.GasLimit,
ChainID: big.NewInt(80001),
}
assert.Equal(t, &types.ConstructionParseResponse{
Expand Down
15 changes: 11 additions & 4 deletions services/construction/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func (a *APIService) ConstructionMetadata(
return nil, svcErrors.WrapErr(svcErrors.ErrGeth, err)
}

// by default, initialize gasLimit to the TransferGasLimit
gasLimit := polygon.TransferGasLimit
to := checkTo
// Only work for ERC20 transfer
Expand All @@ -82,7 +83,7 @@ func (a *APIService) ConstructionMetadata(
to = checkTokenContractAddress

var err *types.Error
gasLimit, err = a.calculateGasLimit(ctx, checkFrom, checkTokenContractAddress, input.Data, nil)
gasLimit, err = a.calculateGasLimit(ctx, checkFrom, checkTokenContractAddress, input.Data, input.Value, input.GasLimit)
if err != nil {
return nil, err
}
Expand All @@ -101,7 +102,7 @@ func (a *APIService) ConstructionMetadata(
to = checkContractAddress

var err *types.Error
gasLimit, err = a.calculateGasLimit(ctx, checkFrom, checkContractAddress, input.Data, input.Value)
gasLimit, err = a.calculateGasLimit(ctx, checkFrom, checkContractAddress, input.Data, input.Value, input.GasLimit)
if err != nil {
return nil, err
}
Expand All @@ -116,7 +117,7 @@ func (a *APIService) ConstructionMetadata(
metadata := &metadata{
Nonce: nonce,
GasPrice: gasPrice,
GasLimit: big.NewInt(int64(gasLimit)),
GasLimit: gasLimit,
Data: input.Data,
Value: input.Value,
To: to,
Expand Down Expand Up @@ -160,14 +161,20 @@ func (a *APIService) calculateNonce(
return nonceInput.Uint64(), nil
}

// calculatesGasLimit calculates the gasLimit for an ERC20 transfer
// calculatesGasLimit calculates the gasLimit for an ERC20 transfer if
// gasLimit is not provided
func (a *APIService) calculateGasLimit(
ctx context.Context,
from string,
to string,
data []byte,
value *big.Int,
gasLimitInput *big.Int,
) (uint64, *types.Error) {
if gasLimitInput != nil {
return gasLimitInput.Uint64(), nil
}

fromAddress := common.HexToAddress(from)
toAddress := common.HexToAddress(to)
var v *big.Int
Expand Down
2 changes: 1 addition & 1 deletion services/construction/payloads.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (a *APIService) ConstructionPayloads(
nonce := metadata.Nonce
gasPrice := metadata.GasPrice
chainID := a.config.Params.ChainID
transferGasLimit := metadata.GasLimit.Uint64()
transferGasLimit := metadata.GasLimit
transferData := metadata.Data

// Ensure valid from address
Expand Down
19 changes: 19 additions & 0 deletions services/construction/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,25 @@ func (a *APIService) ConstructionPreprocess(
}
preprocessOutputOptions.GasPrice = bigObj
}

// Override gas_limit
if v, ok := request.Metadata["gas_limit"]; ok {
stringObj, ok := v.(string)
if !ok {
return nil, svcErrors.WrapErr(
svcErrors.ErrInvalidGasLimit,
fmt.Errorf("%s is not a valid gas_limit string", v),
)
}
bigObj, ok := new(big.Int).SetString(stringObj, 10) //nolint:gomnd
if !ok {
return nil, svcErrors.WrapErr(
svcErrors.ErrInvalidGasLimit,
fmt.Errorf("%s is not a valid gas_limit", v),
)
}
preprocessOutputOptions.GasLimit = bigObj
}

// Only supports ERC20 transfers
currency := fromOp.Amount.Currency
Expand Down
74 changes: 74 additions & 0 deletions services/construction/preprocess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ var (
preprocessData = "0xa9059cbb000000000000000000000000efd3dc58d60af3295b92ecd484caeb3a2f30b3e70000000000000000000000000000000000000000000000000000000000000001" // nolint
preprocessGasPrice = uint64(100000000000)
preprocessGasPriceHex = hexutil.EncodeUint64(preprocessGasPrice)
preprocessGasLimit = uint64(600000)
preprocessGasLimitHex = hexutil.EncodeUint64(preprocessGasLimit)
preprocessGenericData = "0x095ea7b3000000000000000000000000d10a72cf054650931365cc44d912a4fd7525705800000000000000000000000000000000000000000000000000000000000003e8"
methodSignature = "approve(address,uint256)"
methodArgs = []string{"0xD10a72Cf054650931365Cc44D912a4FD75257058", "1000"}
Expand Down Expand Up @@ -201,6 +203,42 @@ func TestPreprocess(t *testing.T) {
},
},
},
"happy path: native currency with gas limit": {
operations: templateOperations(preprocessTransferValue, polygon.Currency),
metadata: map[string]interface{}{
"gas_limit": "600000",
},
expectedResponse: &types.ConstructionPreprocessResponse{
Options: map[string]interface{}{
"from": preprocessFromAddress,
"to": preprocessToAddress,
"value": preprocessTransferValueHex,
"gas_limit": preprocessGasLimitHex,
},
},
},
"happy path: ERC20 currency with gas limit": {
operations: templateOperations(preprocessTransferValue, &types.Currency{
Symbol: "USDC",
Decimals: 18,
Metadata: map[string]interface{}{
"token_address": preprocessTokenContractAddress,
},
}),
metadata: map[string]interface{}{
"gas_limit": "600000",
},
expectedResponse: &types.ConstructionPreprocessResponse{
Options: map[string]interface{}{
"from": preprocessFromAddress,
"to": preprocessToAddress,
"value": "0x0",
"token_address": preprocessTokenContractAddress,
"data": preprocessData,
"gas_limit": preprocessGasLimitHex,
},
},
},
"error: both positive amount": {
operations: func() []*types.Operation {
operations := templateOperations(preprocessTransferValue, polygon.Currency)
Expand Down Expand Up @@ -272,6 +310,42 @@ func TestPreprocess(t *testing.T) {
expectedError: templateError(
svcErrors.ErrInvalidNonce, "invalid_nonce is not a valid nonce"),
},
"error: invalid gas price string": {
operations: templateOperations(preprocessTransferValue, polygon.Currency),
metadata: map[string]interface{}{
"gas_price": map[string]string{},
},
expectedResponse: nil,
expectedError: templateError(
svcErrors.ErrInvalidGasPrice, "map[] is not a valid gas_price string"),
},
"error: invalid gas price": {
operations: templateOperations(preprocessTransferValue, polygon.Currency),
metadata: map[string]interface{}{
"gas_price": "gas_price",
},
expectedResponse: nil,
expectedError: templateError(
svcErrors.ErrInvalidGasPrice, "gas_price is not a valid gas_price"),
},
"error: invalid gas limit string": {
operations: templateOperations(preprocessTransferValue, polygon.Currency),
metadata: map[string]interface{}{
"gas_limit": map[string]string{},
},
expectedResponse: nil,
expectedError: templateError(
svcErrors.ErrInvalidGasLimit, "map[] is not a valid gas_limit string"),
},
"error: invalid gas limit": {
operations: templateOperations(preprocessTransferValue, polygon.Currency),
metadata: map[string]interface{}{
"gas_limit": "gas_limit",
},
expectedResponse: nil,
expectedError: templateError(
svcErrors.ErrInvalidGasLimit, "gas_limit is not a valid gas_limit"),
},
"error: missing token address": {
operations: templateOperations(preprocessTransferValue, &types.Currency{
Symbol: "USDC",
Expand Down
25 changes: 19 additions & 6 deletions services/construction/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type options struct {
ContractAddress string `json:"contract_address,omitempty"`
Value *big.Int `json:"value,omitempty"`
GasPrice *big.Int `json:"gas_price,omitempty"`
GasLimit *big.Int `json:"gas_limit,omitempty"`
MethodSignature string `json:"method_signature,omitempty"`
MethodArgs []string `json:"method_args,omitempty"`
}
Expand All @@ -92,6 +93,7 @@ type optionsWire struct {
ContractAddress string `json:"contract_address,omitempty"`
Value string `json:"value,omitempty"`
GasPrice string `json:"gas_price,omitempty"`
GasLimit string `json:"gas_limit,omitempty"`
MethodSignature string `json:"method_signature,omitempty"`
MethodArgs []string `json:"method_args,omitempty"`
}
Expand Down Expand Up @@ -122,6 +124,10 @@ func (o *options) MarshalJSON() ([]byte, error) {
ow.GasPrice = hexutil.EncodeBig(o.GasPrice)
}

if o.GasLimit != nil {
ow.GasLimit = hexutil.EncodeBig(o.GasLimit)
}

return json.Marshal(ow)
}

Expand Down Expand Up @@ -169,13 +175,21 @@ func (o *options) UnmarshalJSON(data []byte) error {
o.GasPrice = gasPrice
}

if len(ow.GasLimit) > 0 {
gasLimit, err := hexutil.DecodeBig(ow.GasLimit)
if err != nil {
return err
}
o.GasLimit = gasLimit
}

return nil
}

type metadata struct {
Nonce uint64 `json:"nonce"`
GasPrice *big.Int `json:"gas_price"`
GasLimit *big.Int `json:"gas_limit,omitempty"`
GasLimit uint64 `json:"gas_limit,omitempty"`
Data []byte `json:"data,omitempty"`
To string `json:"to,omitempty"`
Value *big.Int `json:"value,omitempty"`
Expand Down Expand Up @@ -203,8 +217,8 @@ func (m *metadata) MarshalJSON() ([]byte, error) {
MethodArgs: m.MethodArgs,
}

if m.GasLimit != nil {
mw.GasLimit = hexutil.EncodeBig(m.GasLimit)
if m.GasLimit > 0 {
mw.GasLimit = hexutil.Uint64(m.GasLimit).String()
}

if len(m.Data) > 0 {
Expand Down Expand Up @@ -241,7 +255,7 @@ func (m *metadata) UnmarshalJSON(data []byte) error {
m.MethodArgs = mw.MethodArgs

if len(mw.GasLimit) > 0 {
gasLimit, err := hexutil.DecodeBig(mw.GasLimit)
gasLimit, err := hexutil.DecodeUint64(mw.GasLimit)
if err != nil {
return err
}
Expand Down Expand Up @@ -270,7 +284,7 @@ func (m *metadata) UnmarshalJSON(data []byte) error {
type parseMetadata struct {
Nonce uint64 `json:"nonce"`
GasPrice *big.Int `json:"gas_price"`
GasLimit uint64 `json:"gas_limit"`
GasLimit uint64 `json:"gas_limit"`
ChainID *big.Int `json:"chain_id"`
}

Expand Down Expand Up @@ -373,6 +387,5 @@ func (t *transaction) UnmarshalJSON(data []byte) error {
t.GasPrice = gasPrice
t.GasLimit = gasLimit
t.ChainID = chainID
t.GasPrice = gasPrice
return nil
}
7 changes: 7 additions & 0 deletions services/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,13 @@ var (
Code: 21, //nolint
Message: "Gas price invalid",
}

// ErrInvalidGasLimit is returned when input gas limit
// is invalid.
ErrInvalidGasLimit = &types.Error{
Code: 22, //nolint
Message: "Gas limit invalid",
}
)

// WrapErr adds details to the types.Error provided. We use a function
Expand Down

0 comments on commit d734dda

Please sign in to comment.