diff --git a/backend/config/backend.go b/backend/config/backend.go index 56b77238..4b9d8954 100644 --- a/backend/config/backend.go +++ b/backend/config/backend.go @@ -6,10 +6,10 @@ import ( ) type BackendScriptsConfig struct { - PlacePixelDevnet string `json:"place_pixel_devnet"` - PlaceExtraPixelsDevnet string `json:"place_extra_pixels_devnet"` - AddTemplateDevnet string `json:"add_template_devnet"` - MintNFTDevnet string `json:"mint_nft_devnet"` + PlacePixelDevnet string `json:"place_pixel_devnet"` + PlaceExtraPixelsDevnet string `json:"place_extra_pixels_devnet"` + AddTemplateDevnet string `json:"add_template_devnet"` + MintNFTDevnet string `json:"mint_nft_devnet"` } type BackendConfig struct { @@ -22,10 +22,10 @@ var DefaultBackendConfig = BackendConfig{ Host: "localhost", Port: 8080, Scripts: BackendScriptsConfig{ - PlacePixelDevnet: "../scripts/place_pixel.sh", - PlaceExtraPixelsDevnet: "../scripts/place_extra_pixels.sh", - AddTemplateDevnet: "../scripts/add_template.sh", - MintNFTDevnet: "../scripts/mint_nft.sh", + PlacePixelDevnet: "../scripts/place_pixel.sh", + PlaceExtraPixelsDevnet: "../scripts/place_extra_pixels.sh", + AddTemplateDevnet: "../scripts/add_template.sh", + MintNFTDevnet: "../scripts/mint_nft.sh", }, } diff --git a/backend/routes/indexer.go b/backend/routes/indexer.go index a64b837c..824e8be2 100644 --- a/backend/routes/indexer.go +++ b/backend/routes/indexer.go @@ -61,12 +61,11 @@ func InitIndexerRoutes() { */ const ( - pixelPlacedEvent = "0x02d7b50ebf415606d77c7e7842546fc13f8acfbfd16f7bcf2bc2d08f54114c23" - nftMintedEvent = "0x030826e0cd9a517f76e857e3f3100fe5b9098e9f8216d3db283fb4c9a641232f" - templateAddedEvent = "0x03e18ec266fe76a2efce73f91228e6e04456b744fc6984c7a6374e417fb4bf59" + pixelPlacedEvent = "0x02d7b50ebf415606d77c7e7842546fc13f8acfbfd16f7bcf2bc2d08f54114c23" + nftMintedEvent = "0x030826e0cd9a517f76e857e3f3100fe5b9098e9f8216d3db283fb4c9a641232f" + templateAddedEvent = "0x03e18ec266fe76a2efce73f91228e6e04456b744fc6984c7a6374e417fb4bf59" ) - // TODO: User might miss some messages between loading canvas and connecting to websocket? func consumeIndexerMsg(w http.ResponseWriter, r *http.Request) { requestBody, err := io.ReadAll(r.Body) @@ -85,20 +84,20 @@ func consumeIndexerMsg(w http.ResponseWriter, r *http.Request) { return } - events := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{}) - - for _, event := range events { - eventKey := event.(map[string]interface{})["event"].(map[string]interface{})["keys"].([]interface{})[0].(string) - if eventKey == pixelPlacedEvent { - processPixelPlacedEvent(event.(map[string]interface{}), w) - } else if eventKey == nftMintedEvent { - processNFTMintedEvent(event.(map[string]interface{}), w) - } else if eventKey == templateAddedEvent { - processTemplateAddedEvent(event.(map[string]interface{}), w) - } else { - fmt.Println("Unknown event key: ", eventKey) - } - } + events := reqBody["data"].(map[string]interface{})["batch"].([]interface{})[0].(map[string]interface{})["events"].([]interface{}) + + for _, event := range events { + eventKey := event.(map[string]interface{})["event"].(map[string]interface{})["keys"].([]interface{})[0].(string) + if eventKey == pixelPlacedEvent { + processPixelPlacedEvent(event.(map[string]interface{}), w) + } else if eventKey == nftMintedEvent { + processNFTMintedEvent(event.(map[string]interface{}), w) + } else if eventKey == templateAddedEvent { + processTemplateAddedEvent(event.(map[string]interface{}), w) + } else { + fmt.Println("Unknown event key: ", eventKey) + } + } } func processPixelPlacedEvent(event map[string]interface{}, w http.ResponseWriter) { @@ -195,222 +194,222 @@ indexer-1 | ] */ func processNFTMintedEvent(event map[string]interface{}, w http.ResponseWriter) { - // TODO: combine high and low token ids + // TODO: combine high and low token ids tokenIdLowHex := event["event"].(map[string]interface{})["keys"].([]interface{})[1] tokenIdHighHex := event["event"].(map[string]interface{})["keys"].([]interface{})[2] - positionHex := event["event"].(map[string]interface{})["data"].([]interface{})[0] - widthHex := event["event"].(map[string]interface{})["data"].([]interface{})[1] - heightHex := event["event"].(map[string]interface{})["data"].([]interface{})[2] - imageHashHex := event["event"].(map[string]interface{})["data"].([]interface{})[3] - blockNumberHex := event["event"].(map[string]interface{})["data"].([]interface{})[4] - minterHex := event["event"].(map[string]interface{})["data"].([]interface{})[5] + positionHex := event["event"].(map[string]interface{})["data"].([]interface{})[0] + widthHex := event["event"].(map[string]interface{})["data"].([]interface{})[1] + heightHex := event["event"].(map[string]interface{})["data"].([]interface{})[2] + imageHashHex := event["event"].(map[string]interface{})["data"].([]interface{})[3] + blockNumberHex := event["event"].(map[string]interface{})["data"].([]interface{})[4] + minterHex := event["event"].(map[string]interface{})["data"].([]interface{})[5] - fmt.Println("NFT minted with token id low: ", tokenIdLowHex, " and token id high: ", tokenIdHighHex) + fmt.Println("NFT minted with token id low: ", tokenIdLowHex, " and token id high: ", tokenIdHighHex) - tokenId, err := strconv.ParseInt(tokenIdLowHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting token id low hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + tokenId, err := strconv.ParseInt(tokenIdLowHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting token id low hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - position, err := strconv.ParseInt(positionHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting position hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + position, err := strconv.ParseInt(positionHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting position hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - width, err := strconv.ParseInt(widthHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting width hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + width, err := strconv.ParseInt(widthHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting width hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - height, err := strconv.ParseInt(heightHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting height hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + height, err := strconv.ParseInt(heightHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting height hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - blockNumber, err := strconv.ParseInt(blockNumberHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting block number hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + blockNumber, err := strconv.ParseInt(blockNumberHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting block number hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - minter := minterHex.(string)[2:] + minter := minterHex.(string)[2:] - fmt.Println("NFT minted with position: ", position, " width: ", width, " height: ", height, " image hash: ", imageHashHex, " block number: ", blockNumber, " minter: ", minter, "tokenId", tokenId) - // Set NFT in postgres - _, err = core.ArtPeaceBackend.Databases.Postgres.Exec(context.Background(), "INSERT INTO NFTs (key, position, width, height, imageHash, blockNumber, minter) VALUES ($1, $2, $3, $4, $5, $6, $7)", tokenId, position, width, height, imageHashHex, blockNumber, minter) - if err != nil { - fmt.Println("Error inserting NFT into postgres: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + fmt.Println("NFT minted with position: ", position, " width: ", width, " height: ", height, " image hash: ", imageHashHex, " block number: ", blockNumber, " minter: ", minter, "tokenId", tokenId) + // Set NFT in postgres + _, err = core.ArtPeaceBackend.Databases.Postgres.Exec(context.Background(), "INSERT INTO NFTs (key, position, width, height, imageHash, blockNumber, minter) VALUES ($1, $2, $3, $4, $5, $6, $7)", tokenId, position, width, height, imageHashHex, blockNumber, minter) + if err != nil { + fmt.Println("Error inserting NFT into postgres: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - // TODO: get image from canvas through starknet rpc? What to do about pending transactions? + // TODO: get image from canvas through starknet rpc? What to do about pending transactions? - // Load image from redis - ctx := context.Background() - // TODO: Better way to get image - canvas, err := core.ArtPeaceBackend.Databases.Redis.Get(ctx, "canvas").Result() - if err != nil { - panic(err) - } + // Load image from redis + ctx := context.Background() + // TODO: Better way to get image + canvas, err := core.ArtPeaceBackend.Databases.Redis.Get(ctx, "canvas").Result() + if err != nil { + panic(err) + } - colorPaletteHex := core.ArtPeaceBackend.CanvasConfig.Colors - colorPalette := make([]color.RGBA, len(colorPaletteHex)) - for idx, colorHex := range colorPaletteHex { - r, err := strconv.ParseInt(colorHex[0:2], 16, 64) - if err != nil { - fmt.Println("Error converting red hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - g, err := strconv.ParseInt(colorHex[2:4], 16, 64) - if err != nil { - fmt.Println("Error converting green hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - b, err := strconv.ParseInt(colorHex[4:6], 16, 64) - if err != nil { - fmt.Println("Error converting blue hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - colorPalette[idx] = color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255} - } - bitWidth := int64(core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth) - startX := int64(position % int64(core.ArtPeaceBackend.CanvasConfig.Canvas.Width)) - startY := int64(position / int64(core.ArtPeaceBackend.CanvasConfig.Canvas.Width)) - oneByteBitOffset := int64(8 - bitWidth) - twoByteBitOffset := int64(16 - bitWidth) - generatedImage := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) - for y := startY; y < startY+height; y++ { - for x := startX; x < startX+width; x++ { - pos := y*int64(core.ArtPeaceBackend.CanvasConfig.Canvas.Width) + x - bitPos := pos * bitWidth - bytePos := bitPos / 8 - bitOffset := bitPos % 8 - if bitOffset <= oneByteBitOffset { - colorIdx := (canvas[bytePos] >> (oneByteBitOffset - bitOffset)) & 0b11111 - generatedImage.Set(int(x-startX), int(y-startY), colorPalette[colorIdx]) - } else { - colorIdx := (((uint16(canvas[bytePos]) << 8) | uint16(canvas[bytePos+1])) >> (twoByteBitOffset - bitOffset)) & 0b11111 - generatedImage.Set(int(x-startX), int(y-startY), colorPalette[colorIdx]) - } - } - } - - // TODO: Path to save image - // Save image to disk - filename := fmt.Sprintf("nft-%d.png", tokenId) - file, err := os.Create(filename) - if err != nil { - fmt.Println("Error creating file: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - defer file.Close() + colorPaletteHex := core.ArtPeaceBackend.CanvasConfig.Colors + colorPalette := make([]color.RGBA, len(colorPaletteHex)) + for idx, colorHex := range colorPaletteHex { + r, err := strconv.ParseInt(colorHex[0:2], 16, 64) + if err != nil { + fmt.Println("Error converting red hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + g, err := strconv.ParseInt(colorHex[2:4], 16, 64) + if err != nil { + fmt.Println("Error converting green hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + b, err := strconv.ParseInt(colorHex[4:6], 16, 64) + if err != nil { + fmt.Println("Error converting blue hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + colorPalette[idx] = color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255} + } + bitWidth := int64(core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth) + startX := int64(position % int64(core.ArtPeaceBackend.CanvasConfig.Canvas.Width)) + startY := int64(position / int64(core.ArtPeaceBackend.CanvasConfig.Canvas.Width)) + oneByteBitOffset := int64(8 - bitWidth) + twoByteBitOffset := int64(16 - bitWidth) + generatedImage := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) + for y := startY; y < startY+height; y++ { + for x := startX; x < startX+width; x++ { + pos := y*int64(core.ArtPeaceBackend.CanvasConfig.Canvas.Width) + x + bitPos := pos * bitWidth + bytePos := bitPos / 8 + bitOffset := bitPos % 8 + if bitOffset <= oneByteBitOffset { + colorIdx := (canvas[bytePos] >> (oneByteBitOffset - bitOffset)) & 0b11111 + generatedImage.Set(int(x-startX), int(y-startY), colorPalette[colorIdx]) + } else { + colorIdx := (((uint16(canvas[bytePos]) << 8) | uint16(canvas[bytePos+1])) >> (twoByteBitOffset - bitOffset)) & 0b11111 + generatedImage.Set(int(x-startX), int(y-startY), colorPalette[colorIdx]) + } + } + } - err = png.Encode(file, generatedImage) - if err != nil { - fmt.Println("Error encoding image: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + // TODO: Path to save image + // Save image to disk + filename := fmt.Sprintf("nft-%d.png", tokenId) + file, err := os.Create(filename) + if err != nil { + fmt.Println("Error creating file: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + defer file.Close() - w.WriteHeader(http.StatusOK) - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte("NFT minted")) + err = png.Encode(file, generatedImage) + if err != nil { + fmt.Println("Error encoding image: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte("NFT minted")) } func processTemplateAddedEvent(event map[string]interface{}, w http.ResponseWriter) { - templateIdHex := event["event"].(map[string]interface{})["keys"].([]interface{})[1] - templateHashHex := event["event"].(map[string]interface{})["data"].([]interface{})[0] - templateNameHex := event["event"].(map[string]interface{})["data"].([]interface{})[1] - templatePositionHex := event["event"].(map[string]interface{})["data"].([]interface{})[2] - templateWidthHex := event["event"].(map[string]interface{})["data"].([]interface{})[3] - templateHeightHex := event["event"].(map[string]interface{})["data"].([]interface{})[4] - // TODO: Combine low and high token ids - templateRewardHighHex := event["event"].(map[string]interface{})["data"].([]interface{})[5] - templateRewardLowHex := event["event"].(map[string]interface{})["data"].([]interface{})[6] - templateRewardTokenHex := event["event"].(map[string]interface{})["data"].([]interface{})[7] - - fmt.Println("Template added with template id: ", templateIdHex, " template hash: ", templateHashHex, "reward: ", templateRewardLowHex, templateRewardHighHex, "name:", templateNameHex) - - templateId, err := strconv.ParseInt(templateIdHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting template id hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + templateIdHex := event["event"].(map[string]interface{})["keys"].([]interface{})[1] + templateHashHex := event["event"].(map[string]interface{})["data"].([]interface{})[0] + templateNameHex := event["event"].(map[string]interface{})["data"].([]interface{})[1] + templatePositionHex := event["event"].(map[string]interface{})["data"].([]interface{})[2] + templateWidthHex := event["event"].(map[string]interface{})["data"].([]interface{})[3] + templateHeightHex := event["event"].(map[string]interface{})["data"].([]interface{})[4] + // TODO: Combine low and high token ids + templateRewardHighHex := event["event"].(map[string]interface{})["data"].([]interface{})[5] + templateRewardLowHex := event["event"].(map[string]interface{})["data"].([]interface{})[6] + templateRewardTokenHex := event["event"].(map[string]interface{})["data"].([]interface{})[7] + + fmt.Println("Template added with template id: ", templateIdHex, " template hash: ", templateHashHex, "reward: ", templateRewardLowHex, templateRewardHighHex, "name:", templateNameHex) + + templateId, err := strconv.ParseInt(templateIdHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting template id hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - // Parse template name hex as bytes encoded in utf-8 - decodedName, err := hex.DecodeString(templateNameHex.(string)[2:]) - if err != nil { - fmt.Println("Error decoding template name hex: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - // Trim off 0s at the start - trimmedName := []byte{} - trimming := true - for _, b := range decodedName { - if b == 0 && trimming { - continue - } - trimming = false - trimmedName = append(trimmedName, b) - } - templateName := string(trimmedName) + // Parse template name hex as bytes encoded in utf-8 + decodedName, err := hex.DecodeString(templateNameHex.(string)[2:]) + if err != nil { + fmt.Println("Error decoding template name hex: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + // Trim off 0s at the start + trimmedName := []byte{} + trimming := true + for _, b := range decodedName { + if b == 0 && trimming { + continue + } + trimming = false + trimmedName = append(trimmedName, b) + } + templateName := string(trimmedName) - templatePosition, err := strconv.ParseInt(templatePositionHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting template position hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + templatePosition, err := strconv.ParseInt(templatePositionHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting template position hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - templateWidth, err := strconv.ParseInt(templateWidthHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting template width hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + templateWidth, err := strconv.ParseInt(templateWidthHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting template width hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - templateHeight, err := strconv.ParseInt(templateHeightHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting template height hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + templateHeight, err := strconv.ParseInt(templateHeightHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting template height hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - templateReward, err := strconv.ParseInt(templateRewardLowHex.(string), 0, 64) - if err != nil { - fmt.Println("Error converting template reward hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + templateReward, err := strconv.ParseInt(templateRewardLowHex.(string), 0, 64) + if err != nil { + fmt.Println("Error converting template reward hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - templateRewardToken := templateRewardTokenHex.(string)[2:] + templateRewardToken := templateRewardTokenHex.(string)[2:] - // Add template to postgres - _, err = core.ArtPeaceBackend.Databases.Postgres.Exec(context.Background(), "INSERT INTO Templates (key, name, hash, position, width, height, reward, rewardToken) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", templateId, templateName, templateHashHex, templatePosition, templateWidth, templateHeight, templateReward, templateRewardToken) - if err != nil { - fmt.Println("Error inserting template into postgres: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + // Add template to postgres + _, err = core.ArtPeaceBackend.Databases.Postgres.Exec(context.Background(), "INSERT INTO Templates (key, name, hash, position, width, height, reward, rewardToken) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", templateId, templateName, templateHashHex, templatePosition, templateWidth, templateHeight, templateReward, templateRewardToken) + if err != nil { + fmt.Println("Error inserting template into postgres: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } - w.WriteHeader(http.StatusOK) - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte("Template added")) + w.WriteHeader(http.StatusOK) + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte("Template added")) } diff --git a/backend/routes/nft.go b/backend/routes/nft.go index 1dbea876..d902325e 100644 --- a/backend/routes/nft.go +++ b/backend/routes/nft.go @@ -14,133 +14,133 @@ import ( ) func InitNFTRoutes() { - http.HandleFunc("/get-nft", getNFT) - http.HandleFunc("/get-nfts", getNFTs) - http.HandleFunc("/get-my-nfts", getMyNFTs) - http.HandleFunc("/mint-nft-devnet", mintNFTDevnet) - // Create a static file server for the nft images - http.Handle("/nft-images/", http.StripPrefix("/nft-images/", http.FileServer(http.Dir(".")))) - //http.HandleFunc("/nft-image", nftImage) + http.HandleFunc("/get-nft", getNFT) + http.HandleFunc("/get-nfts", getNFTs) + http.HandleFunc("/get-my-nfts", getMyNFTs) + http.HandleFunc("/mint-nft-devnet", mintNFTDevnet) + // Create a static file server for the nft images + http.Handle("/nft-images/", http.StripPrefix("/nft-images/", http.FileServer(http.Dir(".")))) + //http.HandleFunc("/nft-image", nftImage) } type NFTData struct { - TokenID int `json:"tokenId"` - Position int `json:"position"` - Width int `json:"width"` - Height int `json:"height"` - ImageHash string `json:"imageHash"` - BlockNumber int `json:"blockNumber"` - Minter string `json:"minter"` + TokenID int `json:"tokenId"` + Position int `json:"position"` + Width int `json:"width"` + Height int `json:"height"` + ImageHash string `json:"imageHash"` + BlockNumber int `json:"blockNumber"` + Minter string `json:"minter"` } func getNFT(w http.ResponseWriter, r *http.Request) { - tokenId := r.URL.Query().Get("tokenId") - - var nftData NFTData - rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), "SELECT * FROM nfts WHERE token_id = $1", tokenId) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - defer rows.Close() - - err = rows.Scan(&nftData.TokenID, &nftData.Position, &nftData.Width, &nftData.Height, &nftData.ImageHash, &nftData.BlockNumber, &nftData.Minter) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - - out, err := json.Marshal(nftData) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - w.Write([]byte(out)) + tokenId := r.URL.Query().Get("tokenId") + + var nftData NFTData + rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), "SELECT * FROM nfts WHERE token_id = $1", tokenId) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + defer rows.Close() + + err = rows.Scan(&nftData.TokenID, &nftData.Position, &nftData.Width, &nftData.Height, &nftData.ImageHash, &nftData.BlockNumber, &nftData.Minter) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + out, err := json.Marshal(nftData) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + w.Write([]byte(out)) } func getMyNFTs(w http.ResponseWriter, r *http.Request) { - address := r.URL.Query().Get("address") - - var nftDatas []NFTData - rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), "SELECT * FROM nfts WHERE minter = $1", address) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - defer rows.Close() - - for rows.Next() { - var nftData NFTData - err = rows.Scan(&nftData.TokenID, &nftData.Position, &nftData.Width, &nftData.Height, &nftData.ImageHash, &nftData.BlockNumber, &nftData.Minter) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - nftDatas = append(nftDatas, nftData) - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - - out, err := json.Marshal(nftDatas) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - w.Write([]byte(out)) + address := r.URL.Query().Get("address") + + var nftDatas []NFTData + rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), "SELECT * FROM nfts WHERE minter = $1", address) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + defer rows.Close() + + for rows.Next() { + var nftData NFTData + err = rows.Scan(&nftData.TokenID, &nftData.Position, &nftData.Width, &nftData.Height, &nftData.ImageHash, &nftData.BlockNumber, &nftData.Minter) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + nftDatas = append(nftDatas, nftData) + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + out, err := json.Marshal(nftDatas) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + w.Write([]byte(out)) } func getNFTs(w http.ResponseWriter, r *http.Request) { - // TODO: Pagination & Likes - var nftDatas []NFTData - rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), "SELECT * FROM nfts") - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - defer rows.Close() - - for rows.Next() { - var nftData NFTData - err = rows.Scan(&nftData.TokenID, &nftData.Position, &nftData.Width, &nftData.Height, &nftData.ImageHash, &nftData.BlockNumber, &nftData.Minter) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - nftDatas = append(nftDatas, nftData) - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - - out, err := json.Marshal(nftDatas) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - w.Write([]byte(out)) + // TODO: Pagination & Likes + var nftDatas []NFTData + rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), "SELECT * FROM nfts") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + defer rows.Close() + + for rows.Next() { + var nftData NFTData + err = rows.Scan(&nftData.TokenID, &nftData.Position, &nftData.Width, &nftData.Height, &nftData.ImageHash, &nftData.BlockNumber, &nftData.Minter) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + nftDatas = append(nftDatas, nftData) + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + out, err := json.Marshal(nftDatas) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + w.Write([]byte(out)) } // func nftImage(w http.ResponseWriter, r *http.Request) { // // Get the png image at location "nft-{tokenId}.png" // tokenId := r.URL.Query().Get("tokenId") // imageLocation := fmt.Sprintf("nft-%s.png", tokenId) -// +// // image, err := os.Open(imageLocation) // if err != nil { // w.WriteHeader(http.StatusInternalServerError) @@ -148,50 +148,50 @@ func getNFTs(w http.ResponseWriter, r *http.Request) { // return // } // defer image.Close() -// +// // w.Header().Set("Access-Control-Allow-Origin", "*") // w.Header().Set("Content-Type", "image/png") // w.WriteHeader(http.StatusOK) -// +// // io.Copy(w, image) // } func mintNFTDevnet(w http.ResponseWriter, r *http.Request) { - reqBody, err := io.ReadAll(r.Body) - if err != nil { - panic(err) - } - var jsonBody map[string]string - err = json.Unmarshal(reqBody, &jsonBody) - if err != nil { - panic(err) - } - - position, err := strconv.Atoi(jsonBody["position"]) - if err != nil { - panic(err) - } - - width, err := strconv.Atoi(jsonBody["width"]) - if err != nil { - panic(err) - } - - height, err := strconv.Atoi(jsonBody["height"]) - if err != nil { - panic(err) - } - - shellCmd := core.ArtPeaceBackend.BackendConfig.Scripts.MintNFTDevnet - contract := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") - - cmd := exec.Command(shellCmd, contract, "mint_nft", strconv.Itoa(position), strconv.Itoa(width), strconv.Itoa(height)) - _, err = cmd.Output() - if err != nil { - fmt.Println("Error executing shell command: ", err) - panic(err) - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte("Minted NFT on devnet")) + reqBody, err := io.ReadAll(r.Body) + if err != nil { + panic(err) + } + var jsonBody map[string]string + err = json.Unmarshal(reqBody, &jsonBody) + if err != nil { + panic(err) + } + + position, err := strconv.Atoi(jsonBody["position"]) + if err != nil { + panic(err) + } + + width, err := strconv.Atoi(jsonBody["width"]) + if err != nil { + panic(err) + } + + height, err := strconv.Atoi(jsonBody["height"]) + if err != nil { + panic(err) + } + + shellCmd := core.ArtPeaceBackend.BackendConfig.Scripts.MintNFTDevnet + contract := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") + + cmd := exec.Command(shellCmd, contract, "mint_nft", strconv.Itoa(position), strconv.Itoa(width), strconv.Itoa(height)) + _, err = cmd.Output() + if err != nil { + fmt.Println("Error executing shell command: ", err) + panic(err) + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte("Minted NFT on devnet")) } diff --git a/backend/routes/pixel.go b/backend/routes/pixel.go index b97730e8..4a7ec789 100644 --- a/backend/routes/pixel.go +++ b/backend/routes/pixel.go @@ -17,7 +17,7 @@ func InitPixelRoutes() { http.HandleFunc("/getPixel", getPixel) http.HandleFunc("/getPixelInfo", getPixelInfo) http.HandleFunc("/placePixelDevnet", placePixelDevnet) - http.HandleFunc("/placeExtraPixelsDevnet", placeExtraPixelsDevnet) + http.HandleFunc("/placeExtraPixelsDevnet", placeExtraPixelsDevnet) http.HandleFunc("/placePixelRedis", placePixelRedis) } @@ -86,47 +86,47 @@ func placePixelDevnet(w http.ResponseWriter, r *http.Request) { } func placeExtraPixelsDevnet(w http.ResponseWriter, r *http.Request) { - // TODO: Disable in production - reqBody, err := io.ReadAll(r.Body) - if err != nil { - panic(err) - } - // TODO: Pixel position instead of x, y - // Json data format: - /* - { - "extraPixels": [ - { "x": 0, "y": 0, "colorId": 1 }, - { "x": 1, "y": 0, "colorId": 2 }, - ] - } - */ - var jsonBody map[string][]map[string]int - err = json.Unmarshal(reqBody, &jsonBody) - if err != nil { - panic(err) - } - - shellCmd := core.ArtPeaceBackend.BackendConfig.Scripts.PlaceExtraPixelsDevnet - contract := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") - - positions := strconv.Itoa(len(jsonBody["extraPixels"])) - colors := strconv.Itoa(len(jsonBody["extraPixels"])) - for _, pixel := range jsonBody["extraPixels"] { - pos := pixel["x"] + pixel["y"] * int(core.ArtPeaceBackend.CanvasConfig.Canvas.Width) - positions += " " + strconv.Itoa(pos) - colors += " " + strconv.Itoa(pixel["colorId"]) - } - - cmd := exec.Command(shellCmd, contract, "place_extra_pixels", positions, colors) - _, err = cmd.Output() - if err != nil { - fmt.Println("Error executing shell command: ", err) - panic(err) - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write([]byte("Extra pixels placed")) + // TODO: Disable in production + reqBody, err := io.ReadAll(r.Body) + if err != nil { + panic(err) + } + // TODO: Pixel position instead of x, y + // Json data format: + /* + { + "extraPixels": [ + { "x": 0, "y": 0, "colorId": 1 }, + { "x": 1, "y": 0, "colorId": 2 }, + ] + } + */ + var jsonBody map[string][]map[string]int + err = json.Unmarshal(reqBody, &jsonBody) + if err != nil { + panic(err) + } + + shellCmd := core.ArtPeaceBackend.BackendConfig.Scripts.PlaceExtraPixelsDevnet + contract := os.Getenv("ART_PEACE_CONTRACT_ADDRESS") + + positions := strconv.Itoa(len(jsonBody["extraPixels"])) + colors := strconv.Itoa(len(jsonBody["extraPixels"])) + for _, pixel := range jsonBody["extraPixels"] { + pos := pixel["x"] + pixel["y"]*int(core.ArtPeaceBackend.CanvasConfig.Canvas.Width) + positions += " " + strconv.Itoa(pos) + colors += " " + strconv.Itoa(pixel["colorId"]) + } + + cmd := exec.Command(shellCmd, contract, "place_extra_pixels", positions, colors) + _, err = cmd.Output() + if err != nil { + fmt.Println("Error executing shell command: ", err) + panic(err) + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write([]byte("Extra pixels placed")) } func placePixelRedis(w http.ResponseWriter, r *http.Request) { diff --git a/backend/routes/routes.go b/backend/routes/routes.go index 4f9a6e99..a45dfd71 100644 --- a/backend/routes/routes.go +++ b/backend/routes/routes.go @@ -8,5 +8,5 @@ func InitRoutes() { InitTemplateRoutes() InitUserRoutes() InitContractRoutes() - InitNFTRoutes() + InitNFTRoutes() } diff --git a/backend/routes/templates.go b/backend/routes/templates.go index c2216ed0..80a86fac 100644 --- a/backend/routes/templates.go +++ b/backend/routes/templates.go @@ -22,11 +22,11 @@ import ( ) func InitTemplateRoutes() { - http.HandleFunc("/get-templates", getTemplates) + http.HandleFunc("/get-templates", getTemplates) http.HandleFunc("/addTemplateImg", addTemplateImg) http.HandleFunc("/add-template-data", addTemplateData) http.HandleFunc("/add-template-devnet", addTemplateDevnet) - http.Handle("/templates/", http.StripPrefix("/templates/", http.FileServer(http.Dir(".")))) + http.Handle("/templates/", http.StripPrefix("/templates/", http.FileServer(http.Dir(".")))) } // TODO: Add specific location for template images @@ -48,46 +48,46 @@ func imageToPixelData(imageData []byte) []byte { } type TemplateData struct { - Key int `json:"key"` - Name string `json:"name"` - Hash string `json:"hash"` - Width int `json:"width"` - Height int `json:"height"` - Position int `json:"position"` - Reward int `json:"reward"` - RewardToken string `json:"rewardToken"` + Key int `json:"key"` + Name string `json:"name"` + Hash string `json:"hash"` + Width int `json:"width"` + Height int `json:"height"` + Position int `json:"position"` + Reward int `json:"reward"` + RewardToken string `json:"rewardToken"` } func getTemplates(w http.ResponseWriter, r *http.Request) { - var templates []TemplateData - rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), "SELECT * FROM templates") - if err != nil { - fmt.Println("Error querying templates: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - defer rows.Close() - - for rows.Next() { - var template TemplateData - err := rows.Scan(&template.Key, &template.Name, &template.Hash, &template.Width, &template.Height, &template.Position, &template.Reward, &template.RewardToken) - if err != nil { - fmt.Println("Error scanning template: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - templates = append(templates, template) - } - - out, err := json.Marshal(templates) - if err != nil { - fmt.Println("Error marshalling templates: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Write(out) + var templates []TemplateData + rows, err := core.ArtPeaceBackend.Databases.Postgres.Query(context.Background(), "SELECT * FROM templates") + if err != nil { + fmt.Println("Error querying templates: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + defer rows.Close() + + for rows.Next() { + var template TemplateData + err := rows.Scan(&template.Key, &template.Name, &template.Hash, &template.Width, &template.Height, &template.Position, &template.Reward, &template.RewardToken) + if err != nil { + fmt.Println("Error scanning template: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + templates = append(templates, template) + } + + out, err := json.Marshal(templates) + if err != nil { + fmt.Println("Error marshalling templates: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Write(out) } func addTemplateImg(w http.ResponseWriter, r *http.Request) { @@ -130,88 +130,88 @@ func addTemplateData(w http.ResponseWriter, r *http.Request) { if err != nil { panic(err) } - // Map like {"width": "64", "height": "64", "image": byte array} + // Map like {"width": "64", "height": "64", "image": byte array} var jsonBody map[string]string err = json.Unmarshal(reqBody, &jsonBody) if err != nil { panic(err) } - width, err := strconv.Atoi(jsonBody["width"]) - if err != nil { - panic(err) - } - - height, err := strconv.Atoi(jsonBody["height"]) - if err != nil { - panic(err) - } - - imageData := jsonBody["image"] - // Split string by comma - imageSplit := strings.Split(imageData, ",") - imageBytes := make([]byte, len(imageSplit)) - for idx, val := range imageSplit { - valInt, err := strconv.Atoi(val) - if err != nil { - panic(err) - } - imageBytes[idx] = byte(valInt) - } + width, err := strconv.Atoi(jsonBody["width"]) + if err != nil { + panic(err) + } + + height, err := strconv.Atoi(jsonBody["height"]) + if err != nil { + panic(err) + } + + imageData := jsonBody["image"] + // Split string by comma + imageSplit := strings.Split(imageData, ",") + imageBytes := make([]byte, len(imageSplit)) + for idx, val := range imageSplit { + valInt, err := strconv.Atoi(val) + if err != nil { + panic(err) + } + imageBytes[idx] = byte(valInt) + } hash := hashTemplateImage(imageBytes) // TODO: Store image hash and pixel data in database - - colorPaletteHex := core.ArtPeaceBackend.CanvasConfig.Colors - colorPalette := make([]color.RGBA, len(colorPaletteHex)) - for idx, colorHex := range colorPaletteHex { - r, err := strconv.ParseInt(colorHex[0:2], 16, 64) - if err != nil { - fmt.Println("Error converting red hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - g, err := strconv.ParseInt(colorHex[2:4], 16, 64) - if err != nil { - fmt.Println("Error converting green hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - b, err := strconv.ParseInt(colorHex[4:6], 16, 64) - if err != nil { - fmt.Println("Error converting blue hex to int: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - colorPalette[idx] = color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255} - } - generatedImage := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) - for y := 0; y < int(height); y++ { - for x := 0; x < int(width); x++ { - pos := y * int(width) + x - colorIdx := int(imageBytes[pos]) - if colorIdx < len(colorPalette) { - generatedImage.Set(x, y, colorPalette[colorIdx]) - } - } - } - - // TODO: Path to store generated image - filename := fmt.Sprintf("template-%s.png", hash) - file, err := os.Create(filename) - if err != nil { - fmt.Println("Error creating file: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - defer file.Close() - - err = png.Encode(file, generatedImage) - if err != nil { - fmt.Println("Error encoding image: ", err) - w.WriteHeader(http.StatusInternalServerError) - return - } + + colorPaletteHex := core.ArtPeaceBackend.CanvasConfig.Colors + colorPalette := make([]color.RGBA, len(colorPaletteHex)) + for idx, colorHex := range colorPaletteHex { + r, err := strconv.ParseInt(colorHex[0:2], 16, 64) + if err != nil { + fmt.Println("Error converting red hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + g, err := strconv.ParseInt(colorHex[2:4], 16, 64) + if err != nil { + fmt.Println("Error converting green hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + b, err := strconv.ParseInt(colorHex[4:6], 16, 64) + if err != nil { + fmt.Println("Error converting blue hex to int: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + colorPalette[idx] = color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255} + } + generatedImage := image.NewRGBA(image.Rect(0, 0, int(width), int(height))) + for y := 0; y < int(height); y++ { + for x := 0; x < int(width); x++ { + pos := y*int(width) + x + colorIdx := int(imageBytes[pos]) + if colorIdx < len(colorPalette) { + generatedImage.Set(x, y, colorPalette[colorIdx]) + } + } + } + + // TODO: Path to store generated image + filename := fmt.Sprintf("template-%s.png", hash) + file, err := os.Create(filename) + if err != nil { + fmt.Println("Error creating file: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + defer file.Close() + + err = png.Encode(file, generatedImage) + if err != nil { + fmt.Println("Error encoding image: ", err) + w.WriteHeader(http.StatusInternalServerError) + return + } w.Header().Set("Access-Control-Allow-Origin", "*") w.Write([]byte(hash)) @@ -229,34 +229,34 @@ func addTemplateDevnet(w http.ResponseWriter, r *http.Request) { panic(err) } - hash := jsonBody["hash"] - - // name to hex encoding using utf-8 bytes - name := jsonBody["name"] - nameHex := fmt.Sprintf("0x%x", name) - - position, err := strconv.Atoi(jsonBody["position"]) - if err != nil { - panic(err) - } - - width, err := strconv.Atoi(jsonBody["width"]) - if err != nil { - panic(err) - } - - height, err := strconv.Atoi(jsonBody["height"]) - if err != nil { - panic(err) - } - - // TODO: u256 - reward, err := strconv.Atoi(jsonBody["reward"]) - if err != nil { - panic(err) - } - - rewardToken := jsonBody["rewardToken"] + hash := jsonBody["hash"] + + // name to hex encoding using utf-8 bytes + name := jsonBody["name"] + nameHex := fmt.Sprintf("0x%x", name) + + position, err := strconv.Atoi(jsonBody["position"]) + if err != nil { + panic(err) + } + + width, err := strconv.Atoi(jsonBody["width"]) + if err != nil { + panic(err) + } + + height, err := strconv.Atoi(jsonBody["height"]) + if err != nil { + panic(err) + } + + // TODO: u256 + reward, err := strconv.Atoi(jsonBody["reward"]) + if err != nil { + panic(err) + } + + rewardToken := jsonBody["rewardToken"] // TODO: Create this script shellCmd := core.ArtPeaceBackend.BackendConfig.Scripts.AddTemplateDevnet diff --git a/onchain/src/art_peace.cairo b/onchain/src/art_peace.cairo index 511a160b..e5c13f0c 100644 --- a/onchain/src/art_peace.cairo +++ b/onchain/src/art_peace.cairo @@ -108,7 +108,9 @@ pub mod ArtPeace { self.day_index.write(0); // TODO: Dev only - remove - let test_address = starknet::contract_address_const::<0x328ced46664355fc4b885ae7011af202313056a7e3d44827fb24c9d3206aaa0>(); + let test_address = starknet::contract_address_const::< + 0x328ced46664355fc4b885ae7011af202313056a7e3d44827fb24c9d3206aaa0 + >(); self.extra_pixels.write(test_address, 1000); // TODO: To config @@ -172,7 +174,10 @@ pub mod ArtPeace { // TODO: Use sender not caller? let caller = starknet::get_caller_address(); // TODO: Only if the user has placed a pixel before? - assert(now - self.last_placed_time.read(caller) >= self.time_between_pixels.read(), 'Pixel not available'); + assert( + now - self.last_placed_time.read(caller) >= self.time_between_pixels.read(), + 'Pixel not available' + ); let pixel = Pixel { color, owner: caller }; self.canvas.write(pos, pixel); self.last_placed_time.write(caller, now); diff --git a/onchain/src/nfts/canvas_nft.cairo b/onchain/src/nfts/canvas_nft.cairo index 2c29c27d..5524a792 100644 --- a/onchain/src/nfts/canvas_nft.cairo +++ b/onchain/src/nfts/canvas_nft.cairo @@ -46,9 +46,7 @@ mod CanvasNFT { } #[constructor] - fn constructor( - ref self: ContractState, name: ByteArray, symbol: ByteArray - ) { + fn constructor(ref self: ContractState, name: ByteArray, symbol: ByteArray) { let base_uri = "test"; // TODO: change to real base uri self.erc721.initializer(name, symbol, base_uri); } @@ -57,10 +55,7 @@ mod CanvasNFT { impl CanvasNFTAdditional of ICanvasNFTAdditional { fn set_canvas_contract(ref self: ContractState, canvas_contract: ContractAddress) { let zero_address = starknet::contract_address_const::<0>(); - assert( - self.art_peace.read() == zero_address, - 'ArtPeace contract already set' - ); + assert(self.art_peace.read() == zero_address, 'ArtPeace contract already set'); self.art_peace.write(canvas_contract); }