diff --git a/docs/api/docs.go b/docs/api/docs.go index 976e34e..9283951 100644 --- a/docs/api/docs.go +++ b/docs/api/docs.go @@ -1548,6 +1548,9 @@ const docTemplate = `{ "deployer": { "type": "string" }, + "deposit_balance": { + "type": "number" + }, "eip_standard": { "type": "string" }, diff --git a/docs/api/swagger.json b/docs/api/swagger.json index 98bef7b..bd8b833 100644 --- a/docs/api/swagger.json +++ b/docs/api/swagger.json @@ -1537,6 +1537,9 @@ "deployer": { "type": "string" }, + "deposit_balance": { + "type": "number" + }, "eip_standard": { "type": "string" }, diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml index 8709858..fc543c8 100644 --- a/docs/api/swagger.yaml +++ b/docs/api/swagger.yaml @@ -87,6 +87,8 @@ definitions: type: string deployer: type: string + deposit_balance: + type: number eip_standard: type: string event_identifiers: diff --git a/plugins/evm/dao/contract.go b/plugins/evm/dao/contract.go index 9b3f9a1..73b81dc 100644 --- a/plugins/evm/dao/contract.go +++ b/plugins/evm/dao/contract.go @@ -9,6 +9,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/itering/subscan/model" + "github.com/itering/subscan/pkg/go-web3/complex/types" + "github.com/itering/subscan/pkg/go-web3/dto" evmABI "github.com/itering/subscan/plugins/evm/abi" evmContract "github.com/itering/subscan/plugins/evm/contract" "github.com/itering/subscan/plugins/evm/feature/delegateProxy" @@ -54,10 +56,11 @@ type Contract struct { Precompile uint `json:"precompile"` CompileSettings datatypes.JSON `json:"CompileSettings"` - EipStandard string `json:"eip_standard" gorm:"size:100"` - ProxyImplementation string `json:"proxy_implementation" gorm:"size:64"` - ConstructorArguments string `json:"constructor_arguments" gorm:"type:string"` - DeployCodeHash string `json:"deploy_code_hash" gorm:"size:70;index:deploy_code_hash;default:'';not null"` + EipStandard string `json:"eip_standard" gorm:"size:100"` + ProxyImplementation string `json:"proxy_implementation" gorm:"size:64"` + ConstructorArguments string `json:"constructor_arguments" gorm:"type:string"` + DeployCodeHash string `json:"deploy_code_hash" gorm:"size:70;index:deploy_code_hash;default:'';not null"` + DepositBalance decimal.Decimal `json:"deposit_balance" gorm:"-"` } type ContractSampleJson struct { @@ -285,12 +288,34 @@ func ContractsByAddr(ctx context.Context, contracts string) (contract *Contract) contract = &dbContract } + if balance, ok := latestEvmContractDepositBalance(ctx, contract.Address); ok { + contract.DepositBalance = balance + } + if len(contract.Abi) > 0 && contract.Abi.String() != "null" { contract.EventIdentifiers = findEventIdentifiers(ctx, contract.Abi) } return } +func latestEvmContractDepositBalance(ctx context.Context, contractAddress string) (decimal.Decimal, bool) { + if web3.RPC == nil || web3.RPC.Eth == nil { + return decimal.Zero, false + } + result, err := web3.RPC.Eth.Call(ctx, &dto.TransactionParameters{ + To: contractAddress, + Data: types.ComplexString("0xc399ec88"), // getDeposit() + }) + if err != nil || result == nil { + return decimal.Zero, false + } + balance, err := result.ToBigInt() + if err != nil || balance == nil { + return decimal.Zero, false + } + return decimal.NewFromBigInt(balance, 0), true +} + func backfillContractFromRuntimeCode(ctx context.Context, contractAddress string) *Contract { if web3.RPC == nil || web3.RPC.Eth == nil { return nil diff --git a/plugins/evm/http/contract_e2e_test.go b/plugins/evm/http/contract_e2e_test.go new file mode 100644 index 0000000..f31f5f4 --- /dev/null +++ b/plugins/evm/http/contract_e2e_test.go @@ -0,0 +1,52 @@ +package http + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/itering/subscan/plugins/evm/dao" + "github.com/shopspring/decimal" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type contractRouteMockServer struct { + MockServer +} + +func (m contractRouteMockServer) ContractsByAddr(_ context.Context, address string) *dao.Contract { + return &dao.Contract{ + Address: address, + VerifyStatus: "perfect", + DepositBalance: decimal.NewFromInt(2), + } +} + +func TestContractRouteReturnsDepositBalance(t *testing.T) { + originalSrv := srv + srv = contractRouteMockServer{} + t.Cleanup(func() { srv = originalSrv }) + + request := httptest.NewRequest( + http.MethodPost, + "/api/plugin/evm/contract", + strings.NewReader(`{"address":"0x0000000000000000000000000000000000000002"}`), + ) + recorder := httptest.NewRecorder() + require.NoError(t, contractHandle(recorder, request)) + require.Equal(t, http.StatusOK, recorder.Code) + + var response struct { + Code int `json:"code"` + Data struct { + DepositBalance decimal.Decimal `json:"deposit_balance"` + } `json:"data"` + } + require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &response)) + require.Zero(t, response.Code) + assert.True(t, response.Data.DepositBalance.Equal(decimal.NewFromInt(2))) +} diff --git a/ui-react/src/pages/contract/[id].tsx b/ui-react/src/pages/contract/[id].tsx index a8ab165..ae33aaf 100644 --- a/ui-react/src/pages/contract/[id].tsx +++ b/ui-react/src/pages/contract/[id].tsx @@ -74,6 +74,13 @@ export default function Page() { +
+
Deposit Balance
+
+ {formatBalanceAmount(new BigNumber(contractData.deposit_balance || 0), token?.decimals)} {token?.symbol} +
+
+ diff --git a/ui-react/src/utils/api.ts b/ui-react/src/utils/api.ts index dfdd1ea..9417a5a 100644 --- a/ui-react/src/utils/api.ts +++ b/ui-react/src/utils/api.ts @@ -629,6 +629,7 @@ export type pvmContractInfoType = { deploy_at: number; deploy_code_hash: string; deployer: string; + deposit_balance: string; eip_standard: string; event_identifiers: any | null; evm_version: string;