Skip to content

Commit a091b65

Browse files
committed
(feat) Add OFAC list check
1 parent 69dc9c1 commit a091b65

File tree

5 files changed

+237
-5
lines changed

5 files changed

+237
-5
lines changed

client/chain/chain.go

+23-4
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ type chainClient struct {
321321

322322
sessionEnabled bool
323323

324+
ofacChecker *OfacChecker
325+
324326
authQueryClient authtypes.QueryClient
325327
authzQueryClient authztypes.QueryClient
326328
bankQueryClient banktypes.QueryClient
@@ -440,15 +442,23 @@ func NewChainClient(
440442
subaccountToNonce: make(map[ethcommon.Hash]uint32),
441443
}
442444

445+
_ = NewTxFactory(ctx).WithSequence(0).WithAccountNumber(0).WithGas(0)
446+
447+
cc.ofacChecker, err = NewOfacChecker()
448+
if err != nil {
449+
return nil, errors.Wrap(err, "Error creating OFAC checker")
450+
}
443451
if cc.canSign {
444452
var err error
445-
446-
cc.accNum, cc.accSeq, err = cc.txFactory.AccountRetriever().GetAccountNumberSequence(ctx, ctx.GetFromAddress())
453+
account, err := cc.txFactory.AccountRetriever().GetAccount(ctx, ctx.GetFromAddress())
447454
if err != nil {
448-
err = errors.Wrap(err, "failed to get initial account num and seq")
455+
err = errors.Wrapf(err, "failed to get account")
449456
return nil, err
450457
}
451-
458+
if cc.ofacChecker.IsBlacklisted(account.GetAddress().String()) {
459+
return nil, errors.Errorf("Address %s is in the OFAC list", account.GetAddress())
460+
}
461+
cc.accNum, cc.accSeq = account.GetAccountNumber(), account.GetSequence()
452462
go cc.runBatchBroadcast()
453463
go cc.syncTimeoutHeight()
454464
}
@@ -1153,6 +1163,9 @@ func (c *chainClient) GetAuthzGrants(ctx context.Context, req authztypes.QueryGr
11531163
}
11541164

11551165
func (c *chainClient) BuildGenericAuthz(granter, grantee, msgtype string, expireIn time.Time) *authztypes.MsgGrant {
1166+
if c.ofacChecker.IsBlacklisted(granter) {
1167+
panic("Address is in the OFAC list") // panics should generally be avoided, but otherwise function signature should be changed
1168+
}
11561169
authz := authztypes.NewGenericAuthorization(msgtype)
11571170
authzAny := codectypes.UnsafePackAny(authz)
11581171
return &authztypes.MsgGrant{
@@ -1184,6 +1197,9 @@ var (
11841197
)
11851198

11861199
func (c *chainClient) BuildExchangeAuthz(granter, grantee string, authzType ExchangeAuthz, subaccountId string, markets []string, expireIn time.Time) *authztypes.MsgGrant {
1200+
if c.ofacChecker.IsBlacklisted(granter) {
1201+
panic("Address is in the OFAC list") // panics should generally be avoided, but otherwise function signature should be changed
1202+
}
11871203
var typedAuthzAny codectypes.Any
11881204
var typedAuthzBytes []byte
11891205
switch authzType {
@@ -1279,6 +1295,9 @@ func (c *chainClient) BuildExchangeBatchUpdateOrdersAuthz(
12791295
derivativeMarkets []string,
12801296
expireIn time.Time,
12811297
) *authztypes.MsgGrant {
1298+
if c.ofacChecker.IsBlacklisted(granter) {
1299+
panic("Address is in the OFAC list") // panics should generally be avoided, but otherwise function signature should be changed
1300+
}
12821301
typedAuthz := &exchangetypes.BatchUpdateOrdersAuthz{
12831302
SubaccountId: subaccountId,
12841303
SpotMarkets: spotMarkets,

client/chain/chain_test.go

+49-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package chain
22

33
import (
4+
"encoding/json"
5+
"io"
46
"os"
57
"testing"
68

9+
"github.com/stretchr/testify/assert"
10+
711
"github.com/InjectiveLabs/sdk-go/client"
812
"github.com/InjectiveLabs/sdk-go/client/common"
913
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
@@ -51,6 +55,51 @@ func createClient(senderAddress cosmtypes.AccAddress, cosmosKeyring keyring.Keyr
5155
return chainClient, err
5256
}
5357

58+
func TestOfacList(t *testing.T) {
59+
network := common.LoadNetwork("testnet", "lb")
60+
tmClient, err := rpchttp.New(network.TmEndpoint, "/websocket")
61+
assert.NoError(t, err)
62+
63+
senderAddress, cosmosKeyring, err := accountForTests()
64+
assert.NoError(t, err)
65+
66+
testList := []string{
67+
senderAddress.String(),
68+
}
69+
jsonData, err := json.Marshal(testList)
70+
assert.NoError(t, err)
71+
SetUp("ofac_test.json")
72+
file, err := os.Create(getOfacListPath())
73+
defer func() {
74+
err = os.Remove(getOfacListPath())
75+
assert.NoError(t, err)
76+
TearDown()
77+
}()
78+
_, err = io.WriteString(file, string(jsonData))
79+
assert.NoError(t, err)
80+
err = file.Close()
81+
assert.NoError(t, err)
82+
clientCtx, err := NewClientContext(
83+
network.ChainId,
84+
senderAddress.String(),
85+
cosmosKeyring,
86+
)
87+
assert.NoError(t, err)
88+
89+
clientCtx = clientCtx.WithNodeURI(network.TmEndpoint).WithClient(tmClient)
90+
91+
testChecker, err := NewOfacChecker()
92+
assert.NoError(t, err)
93+
assert.Equal(t, 1, len(testChecker.ofacList))
94+
95+
_, err = NewChainClient(
96+
clientCtx,
97+
network,
98+
common.OptionGasPrices(client.DefaultGasPriceWithDenom),
99+
)
100+
assert.Error(t, err)
101+
}
102+
54103
func TestDefaultSubaccount(t *testing.T) {
55104
network := common.LoadNetwork("devnet", "lb")
56105
senderAddress, cosmosKeyring, err := accountForTests()
@@ -103,5 +152,4 @@ func TestGetSubaccountWithIndex(t *testing.T) {
103152
if subaccountThirty != expectedSubaccountThirtyIdHash {
104153
t.Error("The subaccount with index 30 was calculated incorrectly")
105154
}
106-
107155
}

client/chain/ofac.go

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package chain
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"net/http"
8+
"os"
9+
"path/filepath"
10+
"strings"
11+
)
12+
13+
const (
14+
defaultOfacListURL = "https://raw.githubusercontent.com/InjectiveLabs/injective-lists/master/wallets/ofac.json"
15+
defaultofacListFilename = "ofac.json"
16+
)
17+
18+
var (
19+
ofacListFilename = defaultofacListFilename
20+
)
21+
22+
type OfacChecker struct {
23+
ofacListPath string
24+
ofacList map[string]bool
25+
}
26+
27+
func NewOfacChecker() (*OfacChecker, error) {
28+
checker := &OfacChecker{
29+
ofacListPath: getOfacListPath(),
30+
}
31+
if _, err := os.Stat(checker.ofacListPath); os.IsNotExist(err) {
32+
if err := DownloadOfacList(); err != nil {
33+
return nil, err
34+
}
35+
}
36+
if err := checker.loadOfacList(); err != nil {
37+
return nil, err
38+
}
39+
return checker, nil
40+
}
41+
42+
func getOfacListPath() string {
43+
currentDirectory, _ := os.Getwd()
44+
for !strings.HasSuffix(currentDirectory, "sdk-go") {
45+
currentDirectory = filepath.Dir(currentDirectory)
46+
}
47+
return filepath.Join(filepath.Join(filepath.Join(currentDirectory, "client"), "metadata"), ofacListFilename)
48+
}
49+
50+
func DownloadOfacList() error {
51+
resp, err := http.Get(defaultOfacListURL)
52+
if err != nil {
53+
return err
54+
}
55+
defer resp.Body.Close()
56+
57+
if resp.StatusCode != http.StatusOK {
58+
return fmt.Errorf("failed to download OFAC list, status code: %d", resp.StatusCode)
59+
}
60+
61+
outFile, err := os.Create(getOfacListPath())
62+
if err != nil {
63+
return err
64+
}
65+
defer outFile.Close()
66+
67+
_, err = io.Copy(outFile, resp.Body)
68+
if err != nil {
69+
return err
70+
}
71+
_, err = outFile.WriteString("\n")
72+
if err != nil {
73+
return err
74+
}
75+
return nil
76+
}
77+
78+
func (oc *OfacChecker) loadOfacList() error {
79+
file, err := os.ReadFile(oc.ofacListPath)
80+
if err != nil {
81+
return err
82+
}
83+
var list []string
84+
err = json.Unmarshal(file, &list)
85+
if err != nil {
86+
return err
87+
}
88+
oc.ofacList = make(map[string]bool)
89+
for _, item := range list {
90+
oc.ofacList[item] = true
91+
}
92+
return nil
93+
}
94+
95+
func (oc *OfacChecker) IsBlacklisted(address string) bool {
96+
return oc.ofacList[address]
97+
}
98+
99+
func SetUp(newOfacListFilename string) {
100+
ofacListFilename = newOfacListFilename
101+
}
102+
103+
func TearDown() {
104+
ofacListFilename = defaultofacListFilename
105+
}

client/metadata/ofac.json

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
[
2+
"0x179f48c78f57a3a78f0608cc9197b8972921d1d2",
3+
"0x1967d8af5bd86a497fb3dd7899a020e47560daaf",
4+
"0x19aa5fe80d33a56d56c78e82ea5e50e5d80b4dff",
5+
"0x19aa5fe80d33a56d56c78e82ea5e50e5d80b4dff",
6+
"0x1da5821544e25c636c1417ba96ade4cf6d2f9b5a",
7+
"0x2f389ce8bd8ff92de3402ffce4691d17fc4f6535",
8+
"0x2f389ce8bd8ff92de3402ffce4691d17fc4f6535",
9+
"0x2f50508a8a3d323b91336fa3ea6ae50e55f32185",
10+
"0x308ed4b7b49797e1a98d3818bff6fe5385410370",
11+
"0x3cbded43efdaf0fc77b9c55f6fc9988fcc9b757d",
12+
"0x3efa30704d2b8bbac821307230376556cf8cc39e",
13+
"0x48549a34ae37b12f6a30566245176994e17c6b4a",
14+
"0x4f47bc496083c727c5fbe3ce9cdf2b0f6496270c",
15+
"0x4f47bc496083c727c5fbe3ce9cdf2b0f6496270c",
16+
"0x4f47bc496083c727c5fbe3ce9cdf2b0f6496270c",
17+
"0x530a64c0ce595026a4a556b703644228179e2d57",
18+
"0x5512d943ed1f7c8a43f3435c85f7ab68b30121b0",
19+
"0x5a7a51bfb49f190e5a6060a5bc6052ac14a3b59f",
20+
"0x5f48c2a71b2cc96e3f0ccae4e39318ff0dc375b2",
21+
"0x6be0ae71e6c41f2f9d0d1a3b8d0f75e6f6a0b46e",
22+
"0x6f1ca141a28907f78ebaa64fb83a9088b02a8352",
23+
"0x746aebc06d2ae31b71ac51429a19d54e797878e9",
24+
"0x77777feddddffc19ff86db637967013e6c6a116c",
25+
"0x797d7ae72ebddcdea2a346c1834e04d1f8df102b",
26+
"0x8576acc5c05d6ce88f4e49bf65bdf0c62f91353c",
27+
"0x901bb9583b24d97e995513c6778dc6888ab6870e",
28+
"0x961c5be54a2ffc17cf4cb021d863c42dacd47fc1",
29+
"0x97b1043abd9e6fc31681635166d430a458d14f9c",
30+
"0x9c2bc757b66f24d60f016b6237f8cdd414a879fa",
31+
"0x9f4cda013e354b8fc285bf4b9a60460cee7f7ea9",
32+
"0xa7e5d5a720f06526557c513402f2e6b5fa20b008",
33+
"0xb6f5ec1a0a9cd1526536d3f0426c429529471f40",
34+
"0xb6f5ec1a0a9cd1526536d3f0426c429529471f40",
35+
"0xb6f5ec1a0a9cd1526536d3f0426c429529471f40",
36+
"0xc455f7fd3e0e12afd51fba5c106909934d8a0e4a",
37+
"0xca0840578f57fe71599d29375e16783424023357",
38+
"0xd0975b32cea532eadddfc9c60481976e39db3472",
39+
"0xd882cfc20f52f2599d84b8e8d58c7fb62cfe344b",
40+
"0xd882cfc20f52f2599d84b8e8d58c7fb62cfe344b",
41+
"0xe1d865c3d669dcc8c57c8d023140cb204e672ee4",
42+
"0xe7aa314c77f4233c18c6cc84384a9247c0cf367b",
43+
"0xed6e0a7e4ac94d976eebfb82ccf777a3c6bad921",
44+
"0xf3701f445b6bdafedbca97d1e477357839e4120d",
45+
"0xfac583c0cf07ea434052c49115a4682172ab6b4f",
46+
"0xfec8a60023265364d066a1212fde3930f6ae8da7",
47+
"0xffbac21a641dcfe4552920138d90f3638b3c9fba"
48+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package main
2+
3+
import (
4+
chainclient "github.com/InjectiveLabs/sdk-go/client/chain"
5+
)
6+
7+
func main() {
8+
err := chainclient.DownloadOfacList()
9+
if err != nil {
10+
panic(err)
11+
}
12+
}

0 commit comments

Comments
 (0)