Skip to content

Commit d926a79

Browse files
committed
upgrade api to v2 etherscan, some lint issues
1 parent f5d8a9e commit d926a79

29 files changed

Lines changed: 1528 additions & 1534 deletions

backend/internal/ingestor/etherscan.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
type EtherscanClient struct {
2020
apiKey string
2121
baseURL string
22+
chainId int
2223
logger *zap.Logger
2324
client *http.Client
2425
limiter *rate.Limiter
@@ -68,18 +69,19 @@ type EtherscanTransferEvent struct {
6869
Topics []string `json:"topics"`
6970
}
7071

71-
func NewEtherscanClient(apiKey string, logger *zap.Logger) *EtherscanClient {
72+
func NewEtherscanClient(apiKey string, chainId int, logger *zap.Logger) *EtherscanClient {
7273
return &EtherscanClient{
7374
apiKey: apiKey,
74-
baseURL: "https://api.etherscan.io/api",
75+
baseURL: "https://api.etherscan.io/v2/api",
76+
chainId: chainId,
7577
logger: logger,
7678
client: &http.Client{Timeout: 10 * time.Second},
7779
limiter: rate.NewLimiter(rate.Every(300*time.Millisecond), 1),
7880
}
7981
}
8082

8183
func (c *EtherscanClient) GetLatestBlockNumber() (uint64, error) {
82-
url := fmt.Sprintf("%s?module=proxy&action=eth_blockNumber&apikey=%s", c.baseURL, c.apiKey)
84+
url := fmt.Sprintf("%s?chainid=%d&module=proxy&action=eth_blockNumber&apikey=%s", c.baseURL, c.chainId, c.apiKey)
8385

8486
resp, err := http.Get(url)
8587
if err != nil {
@@ -283,6 +285,8 @@ func (c *EtherscanClient) makeRequest(ctx context.Context, params map[string]str
283285
}
284286

285287
q := req.URL.Query()
288+
// Add chainId parameter for V2 API
289+
q.Add("chainid", strconv.Itoa(c.chainId))
286290
for k, v := range params {
287291
q.Add(k, v)
288292
}

backend/internal/ingestor/etherscan_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import (
1212

1313
func TestNewEtherscanClient(t *testing.T) {
1414
logger, _ := zap.NewDevelopment()
15-
client := NewEtherscanClient("test_api_key", logger)
15+
client := NewEtherscanClient("test_api_key", 1, logger)
1616

1717
assert.NotNil(t, client)
1818
assert.Equal(t, "test_api_key", client.apiKey)
19-
assert.Equal(t, "https://api.etherscan.io/api", client.baseURL)
19+
assert.Equal(t, "https://api.etherscan.io/v2/api", client.baseURL)
20+
assert.Equal(t, 1, client.chainId)
2021
assert.NotNil(t, client.logger)
2122
assert.NotNil(t, client.client)
2223
assert.NotNil(t, client.limiter)
@@ -25,6 +26,7 @@ func TestNewEtherscanClient(t *testing.T) {
2526
func TestGetLatestBlockNumber(t *testing.T) {
2627
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2728
assert.Equal(t, "/api", r.URL.Path)
29+
assert.Equal(t, "1", r.URL.Query().Get("chainid"))
2830
assert.Equal(t, "proxy", r.URL.Query().Get("module"))
2931
assert.Equal(t, "eth_blockNumber", r.URL.Query().Get("action"))
3032
assert.Equal(t, "test_api_key", r.URL.Query().Get("apikey"))
@@ -35,7 +37,7 @@ func TestGetLatestBlockNumber(t *testing.T) {
3537
defer server.Close()
3638

3739
logger, _ := zap.NewDevelopment()
38-
client := NewEtherscanClient("test_api_key", logger)
40+
client := NewEtherscanClient("test_api_key", 1, logger)
3941
client.baseURL = server.URL + "/api"
4042

4143
blockNumber, err := client.GetLatestBlockNumber()

backend/internal/ingestor/ingestor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func NewIngestor(logger *zap.Logger, sqlDB *sql.DB, apiKey string) *Ingestor {
113113
ingestor := &Ingestor{
114114
logger: logger,
115115
queries: db.New(sqlDB),
116-
etherscanClient: NewEtherscanClient(apiKey, logger),
116+
etherscanClient: NewEtherscanClient(apiKey, 1, logger), // chainId 1 for Ethereum mainnet
117117
pubSub: pubSub,
118118
renderSignal: make(chan struct{}, 1),
119119
maxRetries: 5,

frontend/components/Account.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const Account = ({ triedToEagerConnect }: Props) => {
1717
activate,
1818
chainId,
1919
account,
20-
setError,
2120
} = useWeb3React();
2221

2322
// initialize metamask onboarding
@@ -65,7 +64,8 @@ const Account = ({ triedToEagerConnect }: Props) => {
6564
if (error instanceof UserRejectedRequestError) {
6665
setConnecting(false);
6766
} else {
68-
setError(error);
67+
console.error(error);
68+
setConnecting(false);
6969
}
7070
});
7171
}}
@@ -85,14 +85,16 @@ const Account = ({ triedToEagerConnect }: Props) => {
8585
);
8686
}
8787

88+
const etherscanUrl = chainId
89+
? formatEtherscanLink("Account", [chainId, account])
90+
: `https://etherscan.io/address/${account}`;
91+
8892
return (
8993
<a
90-
{...{
91-
href: formatEtherscanLink("Account", [chainId, account]),
92-
target: "_blank",
93-
rel: "noopener noreferrer",
94-
className: "nes-btn py-1 is-primary text-sm font-semibold transition duration-150"
95-
}}
94+
href={etherscanUrl}
95+
target="_blank"
96+
rel="noopener noreferrer"
97+
className="nes-btn py-1 is-primary text-sm font-semibold transition duration-150"
9698
>
9799
{ENSName || `${shortenIfHex(account, 12)}`}
98100
</a>

frontend/components/Header.tsx

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,13 @@ export default function Header() {
2929
<div className="flex items-center justify-between px-3 md:px-6 py-2 md:py-3">
3030
<div className="flex items-center flex-1">
3131
<div className="flex items-center justify-between w-full md:w-auto">
32-
<Link href="/">
33-
<a className="w-8 h-8 md:h-10 md:w-10">
34-
<span className="sr-only">PixelMap</span>
35-
<img
36-
className="w-full h-auto"
37-
src="/assets/images/logo.png"
38-
alt="PixelMap"
39-
/>
40-
</a>
32+
<Link href="/" className="w-8 h-8 md:h-10 md:w-10">
33+
<span className="sr-only">PixelMap</span>
34+
<img
35+
className="w-full h-auto"
36+
src="/assets/images/logo.png"
37+
alt="PixelMap"
38+
/>
4139
</Link>
4240
</div>
4341

@@ -48,10 +46,12 @@ export default function Header() {
4846
{navigation.map((item) => {
4947
if (item.link) {
5048
return (
51-
<Link key={item.name} href={item.link}>
52-
<a className="inline-flex items-center px-4 py-1 border border-white shadow-sm text-sm font-semibold rounded-full text-white bg-blur hover:opacity-80 transition duration-150">
53-
{item.name}
54-
</a>
49+
<Link
50+
key={item.name}
51+
href={item.link}
52+
className="inline-flex items-center px-4 py-1 border border-white shadow-sm text-sm font-semibold rounded-full text-white bg-blur hover:opacity-80 transition duration-150"
53+
>
54+
{item.name}
5555
</Link>
5656
);
5757
} else {
@@ -69,10 +69,11 @@ export default function Header() {
6969
})}
7070
</div>
7171
{account && (
72-
<Link href="/edit">
73-
<a className="px-6 py-1.5 rounded-full bg-gray-900 bg-opacity-70 border ml-auto text-sm font-bold text-white hover:text-white transition duration-150">
74-
Edit tiles
75-
</a>
72+
<Link
73+
href="/edit"
74+
className="px-6 py-1.5 rounded-full bg-gray-900 bg-opacity-70 border ml-auto text-sm font-bold text-white hover:text-white transition duration-150"
75+
>
76+
Edit tiles
7677
</Link>
7778
)}
7879
</div>
@@ -88,10 +89,12 @@ export default function Header() {
8889
{navigation.map((item) => {
8990
if (item.link) {
9091
return (
91-
<Link key={item.name} href={item.link}>
92-
<a className="text-sm font-semibold text-gray-300 hover:text-white transition duration-150">
93-
{item.name}
94-
</a>
92+
<Link
93+
key={item.name}
94+
href={item.link}
95+
className="text-sm font-semibold text-gray-300 hover:text-white transition duration-150"
96+
>
97+
{item.name}
9598
</Link>
9699
);
97100
} else {
@@ -109,10 +112,11 @@ export default function Header() {
109112
})}
110113

111114
{account && (
112-
<Link href="/edit">
113-
<a className="self-end ml-auto text-sm font-semibold text-gray-300 hover:text-white transition duration-150">
114-
Edit tiles
115-
</a>
115+
<Link
116+
href="/edit"
117+
className="self-end ml-auto text-sm font-semibold text-gray-300 hover:text-white transition duration-150"
118+
>
119+
Edit tiles
116120
</Link>
117121
)}
118122
</div>

frontend/components/ImageDisplay.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@ export default function ImageDisplay({image, cols, rows, maxColors, colorDepth,
3030
rgbBytes = lowerBytesColorDepth(rgbBytes, colorDepth);
3131

3232
//convert computed byte array to color array of hex triplets
33-
let colorArray = [];
33+
let colorArray: string[] = [];
3434
for( let i = 0; i < width * height * 3; i+=3 ) {
3535
colorArray.push(rgbToHexTriplet(rgbBytes[i+0], rgbBytes[i+1], rgbBytes[i+2]));
3636
}
3737
return colorArray;
3838
}
3939

4040
function processTileCode(colorArray: Array<string>, width: number, height: number): Array<string[]> {
41-
let tileArray = new Array(rows * cols).fill([]);
41+
// Initialize with arrays, not a shared reference
42+
let tileArray: string[][] = Array(rows * cols).fill(null).map(() => [] as string[]);
4243

4344
//split data into array of hex triplets broken down for each grid
4445
let pixelRowIndex = 0;
@@ -48,10 +49,9 @@ export default function ImageDisplay({image, cols, rows, maxColors, colorDepth,
4849

4950
for( let i = 0; i < cols; i++ ) {
5051
let index = i + (rowIndex * cols);
51-
let arr = tileArray[index];
5252
let slice = pixelSlice.slice(i * defaultPixelMapImageSize, (i + 1) * defaultPixelMapImageSize);
5353

54-
tileArray[index] = arr.concat(slice);
54+
tileArray[index] = [...tileArray[index], ...slice];
5555
}
5656

5757
pixelRowIndex++;
@@ -120,7 +120,7 @@ export default function ImageDisplay({image, cols, rows, maxColors, colorDepth,
120120
}, [imageColors]);
121121

122122
const gridSelect = () => {
123-
let gridBoxes = [];
123+
let gridBoxes: JSX.Element[] = [];
124124

125125
for( let grid = 0; grid < tileCode.length; grid++) {
126126
gridBoxes.push(

frontend/components/ImageEditorModal.tsx

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import { useState } from 'react'
22

3-
import { Dialog, Switch } from '@headlessui/react'
3+
import { Dialog } from '@headlessui/react'
44

55
import ImageUpload from "./ImageUpload";
66
import GridSelect from "./GridSelect";
77
import ImageDisplay from "./ImageDisplay";
88

9-
export default function ImageEditorModal({isOpen, setIsOpen, tile, changeImage}) {
10-
const [img, setImg] = useState();
9+
type ImageEditorModalProps = {
10+
isOpen: boolean;
11+
setIsOpen: (isOpen: boolean) => void;
12+
tile: { id?: number };
13+
changeImage: (code: string) => void;
14+
};
15+
16+
export default function ImageEditorModal({isOpen, setIsOpen, tile, changeImage}: ImageEditorModalProps) {
17+
const [img, setImg] = useState<string>("");
1118

1219
const [{col, row}, setGrid] = useState({
1320
col: 1,
@@ -20,7 +27,7 @@ export default function ImageEditorModal({isOpen, setIsOpen, tile, changeImage})
2027
pixelSize: 16
2128
});
2229

23-
const handleImageChange = (src: any) => {
30+
const handleImageChange = (src: string) => {
2431
setImg(src);
2532
}
2633

@@ -44,26 +51,27 @@ export default function ImageEditorModal({isOpen, setIsOpen, tile, changeImage})
4451
setIsOpen(true)
4552
}
4653

47-
function updateMaxColors(newMaxColors) {
48-
if(!newMaxColors || isNaN(newMaxColors)) newMaxColors = null;
49-
else if(newMaxColors > 256) newMaxColors = 256;
50-
else if(newMaxColors < 1) newMaxColors = 1;
54+
function updateMaxColors(newMaxColors: number | string) {
55+
let numValue = typeof newMaxColors === 'string' ? parseInt(newMaxColors) : newMaxColors;
56+
if(!numValue || isNaN(numValue)) numValue = 256;
57+
else if(numValue > 256) numValue = 256;
58+
else if(numValue < 1) numValue = 1;
5159
setCompression({
52-
maxColors: newMaxColors,
60+
maxColors: numValue,
5361
colorDepth: colorDepth,
5462
pixelSize: pixelSize
5563
});
5664
}
5765

58-
function updateColorDepth(newColorDepth) {
66+
function updateColorDepth(newColorDepth: number) {
5967
setCompression({
6068
maxColors: maxColors,
6169
colorDepth: newColorDepth,
6270
pixelSize: pixelSize
6371
});
6472
}
6573

66-
function updatePixelSize(newPixelSize) {
74+
function updatePixelSize(newPixelSize: number) {
6775
setCompression({
6876
maxColors: maxColors,
6977
colorDepth: colorDepth,
@@ -128,7 +136,14 @@ export default function ImageEditorModal({isOpen, setIsOpen, tile, changeImage})
128136
<div className="mx-4 lg:inline-block"></div>
129137

130138
<div className="comp-inp">
131-
<input type="number" min="1" max="256" className="comp-inp-num" value={maxColors} onChange={() => { updateMaxColors((event.target as HTMLInputElement).value); }}></input>
139+
<input
140+
type="number"
141+
min="1"
142+
max="256"
143+
className="comp-inp-num"
144+
value={maxColors}
145+
onChange={(e) => { updateMaxColors(e.target.value); }}
146+
/>
132147
<label className="comp-inp-num-label">Colors</label>
133148
</div>
134149
</div>

frontend/components/Map.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import { PixelMapTile } from "@pixelmap/common/types/PixelMapTile";
1111
export default function Map(props: any) {
1212
const [showOwned, setShowOwned] = useState(false);
1313
const [showForSale, setShowForSale] = useState(false);
14-
const [ownedTiles, setOwnedTiles] = useState(false);
15-
const [forSaleTiles, setForSaleTiles] = useState(false);
14+
const [ownedTiles, setOwnedTiles] = useState<PixelMapTile[] | false>(false);
15+
const [forSaleTiles, setForSaleTiles] = useState<PixelMapTile[] | false>(false);
1616
const { account } = useWeb3React();
1717

1818
const toggleForSale = (value: boolean) => {
@@ -30,15 +30,16 @@ export default function Map(props: any) {
3030
props.tiles.filter((tile: PixelMapTile) => {
3131
return (
3232
account &&
33-
account != "" &&
33+
account !== "" &&
34+
tile.owner &&
3435
account.toLowerCase() === tile.owner.toLowerCase()
3536
);
3637
})
3738
);
3839

3940
setForSaleTiles(
4041
props.tiles.filter((tile: PixelMapTile) => {
41-
return tile.openseaPrice && tile.openseaPrice != 0;
42+
return tile.openseaPrice !== undefined && tile.openseaPrice !== 0;
4243
})
4344
);
4445
}, [props.tiles, account]);

frontend/components/SearchBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default function SearchBar() {
4040
</div>
4141
<input
4242
id="desktop-search"
43-
className="nes-input font-semibold text-sm is-dark py-1 pl-6 bg-clip-border my-0 placeholder-gray-300 focus:outline-none focus:bg-blue-500 focus:placeholder-gray-200 transition duration-150"
43+
className="nes-input font-semibold text-sm is-dark py-1 pl-6 bg-clip-border my-0 placeholder-gray-300 focus:outline-none focus:bg-blue-500 focus:placeholder-gray-200 transition duration-150 border-white border-solid"
4444
placeholder="Search tile / address"
4545
type="search"
4646
name="search"

0 commit comments

Comments
 (0)