Skip to content

Commit

Permalink
feat(webhook): add webhook (#2538)
Browse files Browse the repository at this point in the history
* add models and endpoint, lacking logic

* just stuff

* just stuff

* made general db interface

* cleanup

* trying to test

* trying to test

* trying ot fix test

* remove interface{} from gorm models, start tests, rework db interface

* add signature

* secret

* look away for now

* finish db test

* finish tests

* add auth

* remove debugging log

* comments and nits

* lint

* appsecret and appid

* resolve comments

* swagger, lint

* feat(synapse-interface): maintenance aggregator using PAUSED_CHAINS (#2345)

* Aggregate maintenance events for banners and warning message

* Dynamically render countdown progress bars based on PAUSED_CHAIN

* Dynamically rendering banners

* Slightly organize

* ChainPause type applied to enforce maintenance event structure, pass in component messages as a prop

* Working with multiple events

* Add dev comments to MaintenanceBanner; refactor

* Add dev comments for MaintenanceWarningMessage; refactor

* Dev comments

* Organize components

* isChainIncluded util

* Clean

* Add ability to specify paused chains by from/to side (#2346)

* Allow indefinite maintenance components by setting end date to null

* Banners to show indefinitely as well

* Add props to disable banner / warning / countdown

* Implement disable warning

* Implement disable countdown, bridge pause still working

* Example

* Clean

* Update naming on Bridge page

* Update comment for isChainIncluded

* Create maintenance events reading from pausedChains.json

* Remove custom margins to allow Bridge parent gap styling to handle spacing

* Require all props to be defined

* Add Swap to maintenance warning messages

* Update useMaintenanceCountdownProgresses to allow distinction between Swap and Bridge pauses

* Move MaintenanceBanners into LandingPageWrapper so banner appears on all pages

* Add ability to specify whether to pause bridge / swap with maintenance event in json

* Clean

* Unused code

* Update dev comments

* Update pause start/end time name for legibility

* Create type guard to check for paused bridge module

* usePausedBridgeModules

* usePausedBridgeModules to filter out SDK quotes

* Initialize paused routes to handle specific route pauses instead of grouping with chain pauses

* Update paused route structure

* Filter for valid quotes based on paused routes

* Create a Set with paused bridge module names to improve time complexity

* Allow for all bridge modules to be paused with ALL

* Add ability to pause bridge modules for all chains, if chainId is left undefined

* Move json files to /v1/ version control folder

* Compare quotes against paused bridge modules more cleanly

* Paused bridge modules json control working

* Fix pausedChains json

* Create examples folder for pause jsons

* Retrigger build

* Fix banner flashing after clearing

* Add padding to banner Close button

* Update text sizing on progress bar

* Update prop naming to prevent confusion on start/end

* Clear chain pauses to ready PR

* Change json file naming to be more readable

* Use inputWarningMessage prop name to indicate warning placement

* Pause Doge activity using Maintenance, to replace prior Chain pause mechanism

* Doge chain paused chain prop values

* Remove paused from/to chainId constants

* Publish

 - @synapsecns/synapse-interface@0.21.0

* Exempt gh pages (#2541)

Co-authored-by: Trajan0x <trajan0x@users.noreply.github.com>

* Deploy: `FastBridge` to Scroll (#2525)

* chore: add Base to `.env.example`

* chore: add Scroll config

* chore: bump devops dependency

* chore: yarn

* feat: deploy `FastBridge` on scroll

* Publish

 - FastBridge@0.2.1

* fix: update `forge-std` to 1.8.1, remove `ds-test`, use `solhint` for linting (#2545)

* chore: forge-std  v1.8.1, remove ds-test dep

* chore: remove ds-test from remappings

* refactor: state mutability

* chore: add solhint

* chore: yarn

* fix: unused imports

* fix: max line length

* Publish

 - contracts-communication@1.3.1
 - FastBridge@0.2.2
 - @synapsecns/solidity-devops@0.3.3

* chore: remove submodules from `contracts-rfq` (#2547)

* build: install OZ as npm module

* chore: update remappings

* refactor: fix compiler warnings in test contract

* chore: remove forge-std submodule

* chore: remove `openzeppelin-contracts` submodule

* fix: restore padding in `.gitmodules`

* Publish

 - FastBridge@0.2.3

* gogenerate

* Revert "gogenerate"

This reverts commit b40e602.

* im dumb

* generate

* tidy

* update swagger doc

* [goreleaser]

* [goreleaser]

---------

Co-authored-by: shampoobera <shampoo@berachain.com>
Co-authored-by: bigboydiamonds <57741810+bigboydiamonds@users.noreply.github.com>
Co-authored-by: bigboydiamonds <bigboydiamonds@users.noreply.github.com>
Co-authored-by: trajan0x <83933037+trajan0x@users.noreply.github.com>
Co-authored-by: Trajan0x <trajan0x@users.noreply.github.com>
Co-authored-by: χ² <88190723+ChiTimesChi@users.noreply.github.com>
Co-authored-by: ChiTimesChi <ChiTimesChi@users.noreply.github.com>
  • Loading branch information
8 people authored May 9, 2024
1 parent 0782d67 commit a7d430c
Show file tree
Hide file tree
Showing 22 changed files with 974 additions and 40 deletions.
14 changes: 9 additions & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"eslint.workingDirectories": [
{ "directory": "packages/contracts", "changeProcessCWD": true }
{
"directory": "packages/contracts",
"changeProcessCWD": true
}
],
"eslint.nodePath": "./node_modules/eslint/bin/",
"eslint.format.enable": true,
"editorconfig.generateAuto": false,
"files.trimTrailingWhitespace": true,
"solidity.packageDefaultDependenciesContractsDirectory": "contracts",
"solidity.packageDefaultDependenciesDirectory": "lib",
"solidity.compileUsingRemoteVersion": "v0.8.17",
"solidity.formatter": "prettier"
}
"solidity.compileUsingRemoteVersion": "v0.8.17+commit.8df45f5f",
"solidity.formatter": "prettier",
"solidity.defaultCompiler": "remote"
}
93 changes: 93 additions & 0 deletions contrib/screener-api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,29 @@ package client

import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
"time"

"github.com/dubonzi/otelresty"
"github.com/go-resty/resty/v2"
"github.com/google/uuid"
"github.com/synapsecns/sanguine/core/ginhelper"
"github.com/synapsecns/sanguine/core/metrics"
)

var (
// BlacklistEndpoint is the endpoint for blacklisting an address.
BlacklistEndpoint = "/api/data/sync/"
)

// ScreenerClient is an interface for the Screener API.
type ScreenerClient interface {
ScreenAddress(ctx context.Context, ruleset, address string) (blocked bool, err error)
BlacklistAddress(ctx context.Context, appsecret string, appid string, body BlackListBody) (string, error)
}

type clientImpl struct {
Expand All @@ -37,6 +49,7 @@ type blockedResponse struct {
Blocked bool `json:"risk"`
}

// ScreenAddress checks if an address is blocked by the screener.
func (c clientImpl) ScreenAddress(ctx context.Context, ruleset, address string) (bool, error) {
var blockedRes blockedResponse
resp, err := c.rClient.R().
Expand All @@ -54,6 +67,54 @@ func (c clientImpl) ScreenAddress(ctx context.Context, ruleset, address string)
return blockedRes.Blocked, nil
}

// BlackListBody is the json payload that represents a blacklisted address.
type BlackListBody struct {
TypeReq string `json:"typereq"`
ID string `json:"id"`
Data string `json:"data"`
Address string `json:"address"`
Network string `json:"network"`
Tag string `json:"tag"`
Remark string `json:"remark"`
}

type blacklistResponse struct {
Status string `json:"status"`
Error string `json:"error"`
}

func (c clientImpl) BlacklistAddress(ctx context.Context, appsecret string, appid string, body BlackListBody) (string, error) {
var blacklistRes blacklistResponse

nonce := strings.ReplaceAll(uuid.New().String(), "-", "")[:32]
timestamp := fmt.Sprintf("%d", time.Now().Unix())
queryString := ""

signature := GenerateSignature(appsecret, appid, timestamp, nonce, queryString, body)

resp, err := c.rClient.R().
SetContext(ctx).
SetHeader("Content-Type", "application/json").
SetHeader("appid", appid).
SetHeader("timestamp", timestamp).
SetHeader("nonce", nonce).
SetHeader("queryString", queryString).
SetHeader("signature", signature).
SetResult(&blacklistRes).
SetBody(body).
Post(BlacklistEndpoint)

if err != nil {
return resp.Status(), fmt.Errorf("error from server: %s: %w", resp.String(), err)
}

if resp.IsError() {
return resp.Status(), fmt.Errorf("error from server: %s", resp.String())
}

return blacklistRes.Status, nil
}

// NewNoOpClient creates a new no-op client for the Screener API.
// it returns false for every address.
func NewNoOpClient() (ScreenerClient, error) {
Expand All @@ -66,4 +127,36 @@ func (n noOpClient) ScreenAddress(_ context.Context, _, _ string) (bool, error)
return false, nil
}

func (n noOpClient) BlacklistAddress(_ context.Context, _ string, _ string, _ BlackListBody) (string, error) {
return "", nil
}

// GenerateSignature generates a signature for the request.
func GenerateSignature(secret string,
appid string,
timestamp string,
nonce string,
queryString string,
body BlackListBody,
) string {
key := []byte(secret)

// Concatenate the body.
message := fmt.Sprintf(
"%s%s%s%s%s%s%s",
appid,
timestamp,
nonce,
"POST",
BlacklistEndpoint,
queryString,
body,
)

h := hmac.New(sha256.New, key)
h.Write([]byte(message))

return strings.ToLower(hex.EncodeToString(h.Sum(nil)))
}

var _ ScreenerClient = noOpClient{}
4 changes: 4 additions & 0 deletions contrib/screener-api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import "time"

// Config is the configuration for the screener.
type Config struct {
// AppSecret is the app secret
AppSecret string `yaml:"app-secret"`
// AppID is the app id
AppID string `yaml:"app-id"`
// TRMKey is the api key for trmlabs
TRMKey string `yaml:"trm-key"`
// Rules of [caller_type]->risk_type
Expand Down
27 changes: 26 additions & 1 deletion contrib/screener-api/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,29 @@ package db
import (
"context"
"errors"
"github.com/synapsecns/sanguine/contrib/screener-api/trmlabs"
"time"

"github.com/synapsecns/sanguine/contrib/screener-api/trmlabs"
)

// BlacklistedAddressWriterDB provides methods to write blacklisted addresses to the database.
type BlacklistedAddressWriterDB interface {
PutBlacklistedAddress(ctx context.Context, body BlacklistedAddress) error
DeleteBlacklistedAddress(ctx context.Context, id string) error
UpdateBlacklistedAddress(ctx context.Context, id string, body BlacklistedAddress) error
}

// BlacklistedAddressReaderDB provides methods to read blacklisted addresses from the database.
type BlacklistedAddressReaderDB interface {
GetBlacklistedAddress(ctx context.Context, address string) (*BlacklistedAddress, error)
}

// BlacklistedAddressDB is the interface for reading and writing blacklisted addresses to the database.
type BlacklistedAddressDB interface {
BlacklistedAddressWriterDB
BlacklistedAddressReaderDB
}

// RuleWriterDB is the interface for writing rules to the database.
type RuleWriterDB interface {
PutAddressIndicators(ctx context.Context, address string, riskIndicator []trmlabs.AddressRiskIndicator) error
Expand All @@ -24,5 +43,11 @@ type RuleDB interface {
RuleReaderDB
}

// DB is the general database interface for the screener-api.
type DB interface {
BlacklistedAddressDB
RuleDB
}

// ErrNoAddressNotCached is returned when an address is not cached.
var ErrNoAddressNotCached = errors.New("address not cached")
57 changes: 53 additions & 4 deletions contrib/screener-api/db/db_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package db_test

import (
"time"

"github.com/brianvoe/gofakeit/v6"
"github.com/synapsecns/sanguine/contrib/screener-api/db"
"github.com/synapsecns/sanguine/contrib/screener-api/trmlabs"
"time"
"gorm.io/gorm"
)

func (d *DBSuite) TestEmpty() {
d.RunOnAllDBs(func(testDB db.RuleDB) {
d.RunOnAllDBs(func(testDB db.DB) {
testAddress := gofakeit.BitcoinAddress()

// 5 mins ago
Expand All @@ -28,8 +30,8 @@ func (d *DBSuite) TestEmpty() {
})
}

func (d *DBSuite) TestAdressUpdate() {
d.RunOnAllDBs(func(testDB db.RuleDB) {
func (d *DBSuite) TestAddressUpdate() {
d.RunOnAllDBs(func(testDB db.DB) {
testAddress := gofakeit.BitcoinAddress()

// 5 mins ago
Expand Down Expand Up @@ -64,3 +66,50 @@ func (d *DBSuite) TestAdressUpdate() {
d.Require().Error(err, db.ErrNoAddressNotCached)
})
}

func (d *DBSuite) TestBlacklist() {
d.RunOnAllDBs(func(testDB db.DB) {
testAddress := gofakeit.BitcoinAddress()

blacklistBody := db.BlacklistedAddress{
TypeReq: "create",
ID: "testId",
Address: testAddress,
Network: "bitcoin",
Tag: "testTag",
Remark: "testRemark",
}

// blacklist the address
err := testDB.PutBlacklistedAddress(d.GetTestContext(), blacklistBody)
d.Require().NoError(err)
blacklistedAddress, err := testDB.GetBlacklistedAddress(d.GetTestContext(), blacklistBody.Address)
d.Require().NoError(err)
d.Require().NotNil(blacklistedAddress)

// update the address
blacklistBody.TypeReq = "update"
blacklistBody.Remark = "testRemarkUpdated"
err = testDB.UpdateBlacklistedAddress(d.GetTestContext(), blacklistBody.ID, blacklistBody)
d.Require().NoError(err)

// check to make sure it updated
blacklistedAddress, err = testDB.GetBlacklistedAddress(d.GetTestContext(), blacklistBody.Address)
d.Require().NoError(err)
d.Require().NotNil(blacklistedAddress)
d.Require().Equal("testRemarkUpdated", blacklistedAddress.Remark)

// check for non blacklisted address
res, err := testDB.GetBlacklistedAddress(d.GetTestContext(), gofakeit.BitcoinAddress())
d.Require().EqualError(err, gorm.ErrRecordNotFound.Error())
d.Require().Nil(res)

// delete it
err = testDB.DeleteBlacklistedAddress(d.GetTestContext(), blacklistBody.ID)
d.Require().NoError(err)

// delete nonexistent
err = testDB.DeleteBlacklistedAddress(d.GetTestContext(), "NonexistentId")
d.Require().NoError(err)
})
}
19 changes: 17 additions & 2 deletions contrib/screener-api/db/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,27 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/synapsecns/sanguine/contrib/screener-api/trmlabs"
"gorm.io/gorm/schema"
"strings"
"time"

"github.com/synapsecns/sanguine/contrib/screener-api/trmlabs"
"gorm.io/gorm/schema"
)

// BlacklistedAddress is a blacklisted address.
type BlacklistedAddress struct {
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`

TypeReq string `gorm:"column:typereq" json:"typereq"`
ID string `gorm:"column:id;primary_key" json:"id"`
Data string `gorm:"column:data" json:"data"`
Address string `gorm:"column:address" json:"address"`
Network string `gorm:"column:network" json:"network"`
Tag string `gorm:"column:tag" json:"tag"`
Remark string `gorm:"column:remark" json:"remark"`
}

// AddressIndicators is the address indicators for a given address.
type AddressIndicators struct {
CreatedAt time.Time
Expand Down
Loading

0 comments on commit a7d430c

Please sign in to comment.