Skip to content

Commit

Permalink
update specs
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewkmin committed Nov 8, 2022
1 parent 9343a74 commit e751d28
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 3 deletions.
217 changes: 215 additions & 2 deletions services/construction/construction_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ var (
transferGasTipHex = hexutil.EncodeUint64(transferGasTip) // 0x9502F9000
transferGasTipMultipliedHex = hexutil.EncodeUint64(transferGasTipMultiplied) // 0x12A05F2000
transferGasTipEstimate = uint64(3000000000) // 3 gwei
transferGasCapWithTip = transferGasTipMultiplied + baseFeeMultiplied // 160 gwei -- 2*2 * 400000000000gwei + // 2*GasTip + 2*BaseFee
transferGasCapWithTipHex = hexutil.EncodeUint64(transferGasCapWithTip) // 0x2540BE4000
transferGasCapWithTip = transferGasTipMultiplied + baseFeeMultiplied // 80000000016 wei
transferGasCapWithTipHex = hexutil.EncodeUint64(transferGasCapWithTip) // 0x12a05f2010
minGasCap = big.NewInt(40000000000) // 40 gwei
baseFee = uint64(8) // 8 wei (testnet)
baseFeeMultiplied = uint64(16) // 16 wei (testnet)
Expand Down Expand Up @@ -576,6 +576,219 @@ func TestConstructionFlowWithInputNonce(t *testing.T) {
mockClient.AssertExpectations(t)
}

func TestConstructionFlowWithInputNonceAndGasTip(t *testing.T) {
/** Leaving useful reference variables here commented in order to avoid compiler complaints */

// overriddenTransferGasTip := uint64(123000000000) // 123 gwei, overridden
overriddenTransferGasTipMultiplied := uint64(246000000000) // 246 gwei (multiplied)
// overriddenTransferGasTipHex := hexutil.EncodeUint64(overriddenTransferGasTip) // 0x1ca35f0e00
// overriddenTransferGasTipMultipliedHex := hexutil.EncodeUint64(overriddenTransferGasTipMultiplied) // 0x3946be1c00
overriddenTransferGasTipEstimate := uint64(3000000000) // 3 gwei
overriddenTransferGasCapWithTip := overriddenTransferGasTipMultiplied + baseFeeMultiplied // 246 gwei + 16 wei == 246000000016
// overriddenTransferGasCapWithTipHex := hexutil.EncodeUint64(overriddenTransferGasCapWithTip) // 0x3946be1c10

tipMultiplier = 2.0
networkIdentifier = &types.NetworkIdentifier{
Network: polygon.TestnetNetwork,
Blockchain: polygon.Blockchain,
}

cfg := &configuration.Configuration{
Mode: configuration.Online,
Network: networkIdentifier,
Params: params.GoerliChainConfig,
}
cfg.Params.ChainID.SetString(configuration.MumbaiChainID, 10)

mockClient := &mocks.Client{}
servicer := NewAPIService(cfg, mockClient)
ctx := context.Background()

// Test Derive
publicKey := &types.PublicKey{
Bytes: forceHexDecode(
t,
transferAddress.compressedPublicKey,
),
CurveType: types.Secp256k1,
}
deriveResponse, err := servicer.ConstructionDerive(ctx, &types.ConstructionDeriveRequest{
NetworkIdentifier: networkIdentifier,
PublicKey: publicKey,
})
assert.Nil(t, err)
assert.Equal(t, &types.ConstructionDeriveResponse{
AccountIdentifier: &types.AccountIdentifier{
Address: transferAddress.address,
},
}, deriveResponse)

// Test Preprocess
intent := `[{"operation_identifier":{"index":0},"type":"CALL","account":{"address":"0xda75C156Bc4b518ac4b91Ee942BE2B2e2e36e8C1"},"amount":{"value":"-1000","currency":{"symbol":"MATIC","decimals":18}}},{"operation_identifier":{"index":1},"related_operations":[{"index":0}],"type":"CALL","account":{"address":"0x3Fa177c2E87Cb24148EC403921dB577d140CC07c"},"amount":{"value":"1000","currency":{"symbol":"MATIC","decimals":18}}}]`
var ops []*types.Operation
assert.NoError(t, json.Unmarshal([]byte(intent), &ops))
preprocessResponse, err := servicer.ConstructionPreprocess(
ctx,
&types.ConstructionPreprocessRequest{
NetworkIdentifier: networkIdentifier,
Operations: ops,
Metadata: map[string]interface{}{"nonce": "1","gas_tip": "123000000000"},
},
)
assert.Nil(t, err)
optionsRaw := `{"from":"0xda75C156Bc4b518ac4b91Ee942BE2B2e2e36e8C1","nonce":"0x1","to":"0x3Fa177c2E87Cb24148EC403921dB577d140CC07c","value":"0x3e8","gas_tip":"0x1ca35f0e00"}`
var options options
assert.NoError(t, json.Unmarshal([]byte(optionsRaw), &options))
assert.Equal(t, &types.ConstructionPreprocessResponse{
Options: forceMarshalMap(t, &options),
}, preprocessResponse)

// Test Metadata
metadata := &metadata{
GasLimit: 21000,
GasTip: big.NewInt(int64(overriddenTransferGasTipMultiplied)),
GasCap: big.NewInt(int64(overriddenTransferGasCapWithTip)),
Nonce: 1,
To: constructionToAddress,
Value: big.NewInt(1000),
}

var blockNum *big.Int = nil

mockClient.On(
"BlockHeader",
ctx,
blockNum,
).Return(
&header,
nil,
).Once()
mockClient.On(
"SuggestGasTipCap",
ctx,
).Return(
big.NewInt(int64(overriddenTransferGasTipEstimate)),
nil,
).Once()
metadataResponse, err := servicer.ConstructionMetadata(ctx, &types.ConstructionMetadataRequest{
NetworkIdentifier: networkIdentifier,
Options: preprocessResponse.Options,
})
assert.Nil(t, err)
assert.Equal(t, &types.ConstructionMetadataResponse{
Metadata: forceMarshalMap(t, metadata),
SuggestedFee: []*types.Amount{
{
Value: "5166000000336000",
Currency: polygon.Currency,
},
},
}, metadataResponse)

// Test Payloads
unsignedRaw := `{"from":"0xda75C156Bc4b518ac4b91Ee942BE2B2e2e36e8C1","to":"0x3Fa177c2E87Cb24148EC403921dB577d140CC07c","value":"0x3e8","data":"0x","nonce":"0x1","max_fee_per_gas":"0x3946be1c10","max_priority_fee_per_gas":"0x3946be1c00","gas":"0x5208","chain_id":"0x13881"}`
payloadsResponse, err := servicer.ConstructionPayloads(ctx, &types.ConstructionPayloadsRequest{
NetworkIdentifier: networkIdentifier,
Operations: ops,
Metadata: forceMarshalMap(t, metadata),
})
assert.Nil(t, err)
payloadsRaw := `[{"address":"0xda75C156Bc4b518ac4b91Ee942BE2B2e2e36e8C1","hex_bytes":"813f93a233d21e454bde73920eeedd0ecffdda5c1792635c50810f9b4c15cbca","account_identifier":{"address":"0xda75C156Bc4b518ac4b91Ee942BE2B2e2e36e8C1"},"signature_type":"ecdsa_recovery"}]`
var payloads []*types.SigningPayload
assert.NoError(t, json.Unmarshal([]byte(payloadsRaw), &payloads))
assert.Equal(t, &types.ConstructionPayloadsResponse{
UnsignedTransaction: unsignedRaw,
Payloads: payloads,
}, payloadsResponse)

// Test Parse Unsigned
parseOpsRaw := `[{"operation_identifier":{"index":0},"type":"CALL","account":{"address":"0xda75C156Bc4b518ac4b91Ee942BE2B2e2e36e8C1"},"amount":{"value":"-1000","currency":{"symbol":"MATIC","decimals":18}}},{"operation_identifier":{"index":1},"related_operations":[{"index":0}],"type":"CALL","account":{"address":"0x3Fa177c2E87Cb24148EC403921dB577d140CC07c"},"amount":{"value":"1000","currency":{"symbol":"MATIC","decimals":18}}}]`
var parseOps []*types.Operation
assert.NoError(t, json.Unmarshal([]byte(parseOpsRaw), &parseOps))
parseUnsignedResponse, err := servicer.ConstructionParse(ctx, &types.ConstructionParseRequest{
NetworkIdentifier: networkIdentifier,
Signed: false,
Transaction: unsignedRaw,
})
assert.Nil(t, err)
parseMetadata := &parseMetadata{
Nonce: metadata.Nonce,
GasLimit: metadata.GasLimit,
GasCap: metadata.GasCap,
GasTip: metadata.GasTip,
ChainID: big.NewInt(80001),
}
assert.Equal(t, &types.ConstructionParseResponse{
Operations: parseOps,
AccountIdentifierSigners: []*types.AccountIdentifier{},
Metadata: forceMarshalMap(t, parseMetadata),
}, parseUnsignedResponse)

// Test Combine
signaturesRaw := `[{"hex_bytes":"ae4c4901ffa532ed1c73688d3b2af602fbba6f1484cbd5ed2cb9cd0aeac1935a152a40d9fab96a9e7c2f9969862fb6a9fbfbd5c68cb1d044b37e61e635fc4a7901","public_key":{"hex_bytes":"df5c7854e2264f641773f12fa3ce186ef1ebb294a7842ae7f3ef46ba502f7bffc990442f989d091ddaac352651de2d6f20fa0e65cc32d5283777177a41f51b7d","curve_type":"secp256k1"},"signing_payload":{"hex_bytes":"813f93a233d21e454bde73920eeedd0ecffdda5c1792635c50810f9b4c15cbca","address":"0xda75C156Bc4b518ac4b91Ee942BE2B2e2e36e8C1"},"signature_type":"ecdsa_recovery"}]`
var signatures []*types.Signature
assert.NoError(t, json.Unmarshal([]byte(signaturesRaw), &signatures))
signedRaw := `{"type":"0x2","nonce":"0x1","gasPrice":null,"maxPriorityFeePerGas":"0x3946be1c00","maxFeePerGas":"0x3946be1c10","gas":"0x5208","value":"0x3e8","input":"0x","v":"0x1","r":"0xae4c4901ffa532ed1c73688d3b2af602fbba6f1484cbd5ed2cb9cd0aeac1935a","s":"0x152a40d9fab96a9e7c2f9969862fb6a9fbfbd5c68cb1d044b37e61e635fc4a79","to":"0x3fa177c2e87cb24148ec403921db577d140cc07c","chainId":"0x13881","accessList":[],"hash":"0x46ccfdf9713c2110ae5e34449b4682e922706f345a61827a7de13c67957f43d1"}` // nolint
combineResponse, err := servicer.ConstructionCombine(ctx, &types.ConstructionCombineRequest{
NetworkIdentifier: networkIdentifier,
UnsignedTransaction: unsignedRaw,
Signatures: signatures,
})
assert.Nil(t, err)
assert.Equal(t, &types.ConstructionCombineResponse{
SignedTransaction: signedRaw,
}, combineResponse)

// Test Parse Signed
var parseSignedOps []*types.Operation
assert.NoError(t, json.Unmarshal([]byte(parseOpsRaw), &parseSignedOps))
parseSignedResponse, err := servicer.ConstructionParse(ctx, &types.ConstructionParseRequest{
NetworkIdentifier: networkIdentifier,
Signed: true,
Transaction: signedRaw,
})
assert.Nil(t, err)
assert.Equal(t, &types.ConstructionParseResponse{
Operations: parseSignedOps,
AccountIdentifierSigners: []*types.AccountIdentifier{
{Address: constructionFromAddress},
},
Metadata: forceMarshalMap(t, parseMetadata),
}, parseSignedResponse)

// Test Hash
transactionIdentifier := &types.TransactionIdentifier{
Hash: "0x46ccfdf9713c2110ae5e34449b4682e922706f345a61827a7de13c67957f43d1",
}
hashResponse, err := servicer.ConstructionHash(ctx, &types.ConstructionHashRequest{
NetworkIdentifier: networkIdentifier,
SignedTransaction: signedRaw,
})
assert.Nil(t, err)
assert.Equal(t, &types.TransactionIdentifierResponse{
TransactionIdentifier: transactionIdentifier,
}, hashResponse)

// Test Submit
mockClient.On(
"SendTransaction",
ctx,
mock.Anything, // can't test ethTx here because it contains "time"
).Return(
nil,
)
submitResponse, err := servicer.ConstructionSubmit(ctx, &types.ConstructionSubmitRequest{
NetworkIdentifier: networkIdentifier,
SignedTransaction: signedRaw,
})
assert.Nil(t, err)
assert.Equal(t, &types.TransactionIdentifierResponse{
TransactionIdentifier: transactionIdentifier,
}, submitResponse)

mockClient.AssertExpectations(t)
}

func templateError(error *types.Error, context string) *types.Error {
return &types.Error{
Code: error.Code,
Expand Down
2 changes: 1 addition & 1 deletion services/construction/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func TestMetadata(t *testing.T) {
},
},
},
"happy path: native currency with low estimated gas tip overridden to 30 gwei": {
"happy path: native currency with low estimated gas tip overridden to 40 gwei": {
options: map[string]interface{}{
"from": metadataFrom,
"to": metadataTo,
Expand Down
40 changes: 40 additions & 0 deletions services/construction/preprocess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@ func TestPreprocess(t *testing.T) {
},
},
},
"happy path: native currency with nonce and gas_tip": {
operations: templateOperations(preprocessTransferValue, polygon.Currency),
metadata: map[string]interface{}{
"nonce": "1",
"gas_tip": "40000000000",
},
expectedResponse: &types.ConstructionPreprocessResponse{
Options: map[string]interface{}{
"from": preprocessFromAddress,
"to": preprocessToAddress,
"value": preprocessTransferValueHex,
"nonce": "0x1",
"gas_tip": transferGasTipHex, // hex of 40000000000
},
},
},
"happy path: ERC20 currency with nonce": {
operations: templateOperations(preprocessTransferValue, &types.Currency{
Symbol: "USDC",
Expand All @@ -129,6 +145,30 @@ func TestPreprocess(t *testing.T) {
},
},
},
"happy path: ERC20 currency with nonce and gas_tip": {
operations: templateOperations(preprocessTransferValue, &types.Currency{
Symbol: "USDC",
Decimals: 18,
Metadata: map[string]interface{}{
"token_address": preprocessTokenContractAddress,
},
}),
metadata: map[string]interface{}{
"nonce": "34",
"gas_tip": "40000000000",
},
expectedResponse: &types.ConstructionPreprocessResponse{
Options: map[string]interface{}{
"from": preprocessFromAddress,
"to": preprocessToAddress,
"value": "0x0",
"token_address": preprocessTokenContractAddress,
"data": preprocessData,
"nonce": "0x22",
"gas_tip": transferGasTipHex, // hex of 40000000000
},
},
},
"happy path: Generic Contract call": {
operations: templateOperations(preprocessTransferValue, polygon.Currency),
metadata: map[string]interface{}{
Expand Down

0 comments on commit e751d28

Please sign in to comment.