Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the branch name to canvasOnchain and also write a readme file in the hardhat folder for description #32

Merged
merged 13 commits into from
Dec 17, 2024
Merged
2 changes: 2 additions & 0 deletions package.json
phipsae marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes to this file, pls.

Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@
},
"packageManager": "[email protected]",
"devDependencies": {
"@nomicfoundation/hardhat-network-helpers": "^1.0.12",
phipsae marked this conversation as resolved.
Show resolved Hide resolved
"husky": "^9.1.6",
"lint-staged": "^15.2.10"
},
"engines": {
"node": ">=18.18.0"
},
"dependencies": {
"hardhat": "^2.22.17",
"react-icons": "^5.3.0"
}
}
48 changes: 48 additions & 0 deletions packages/hardhat/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## PixelCanvas: Decentralized Collaborative Pixel Art Smart Contract

### Contract Overview
A collaborative on-chain pixel art platform implemented as an Ethereum smart contract, enabling users to create and modify a shared 64x64 pixel canvas.

### Technical Specifications
- **Blockchain**: Ethereum
- **Solidity Version**: ^0.8.20
- **Dependencies**: OpenZeppelin Ownable
- **Canvas Dimensions**: 64x64 pixels
- **Color Palette**: 8 predefined colors

### Key Components

#### Pixel Structure
```solidity
struct Pixel {
address author; // Address of pixel creator
Color color; // Chosen color from enum
uint256 timestamp;// Block timestamp of pixel placement
}

Core Functionalities
1. Pixel Placement

Function: placePixel(uint256 x, uint256 y, Color color)
Validates coordinate boundaries
Allows user to place a single pixel
Emits PixelPlaced event for tracking

2. Canvas Retrieval

getPixel(x, y): Retrieves individual pixel information
getCanvasSnapshot(): Returns entire canvas state

3. Initialization
Test the CanvasOnchain contract
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Test the CanvasOnchain contract
Test the PixelCanvas contract

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[RESOLVED]

Includes default Buidlguidl Batch11 logo on contract deployment
Demonstrates initial canvas state

Known Limitations

Fixed 64x64 canvas size
Limited 8-color palette
No pixel modification after placement



122 changes: 122 additions & 0 deletions packages/hardhat/contracts/CanvasOnchain.sol
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filename is not matching the contract name

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[RESOLVED]

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/Ownable.sol";

contract PixelCanvas is Ownable {
// Canvas Dimensions
uint256 public constant CANVAS_WIDTH = 64;
uint256 public constant CANVAS_HEIGHT = 64;

// Color Palette (Limited Options)
enum Color {
WHITE,
BLACK,
RED,
GREEN,
BLUE,
YELLOW,
PURPLE,
ORANGE
}

// Pixel Structure
struct Pixel {
address author;
Color color;
uint256 timestamp;
}

// 2D Mapping to store pixels
Pixel[CANVAS_WIDTH][CANVAS_HEIGHT] public canvas;

// Events
event PixelPlaced(address indexed author, uint256 x, uint256 y, Color color);

// Constructor to initialize default Buidlguidl Batch11 drawing
constructor() Ownable(msg.sender){

// Initial drawing representing Buidlguidl Batch11 logo
initializeBuidlGuidlLogo();
}

/**
* @dev Initialize a default Buidlguidl Batch11 inspired pixel art
* This is a simplified representation and can be customized
*/
function initializeBuidlGuidlLogo() private {
// B letter representation
for (uint256 x = 10; x < 20; x++) {
for (uint256 y = 10; y < 50; y++) {
canvas[x][y] = Pixel({
author: owner(),
color: Color.BLUE,
timestamp: block.timestamp
});
}
}

// 11 representation with some pixels
for (uint256 x = 30; x < 40; x++) {
for (uint256 y = 20; y < 30; y++) {
canvas[x][y] = Pixel({
author: owner(),
color: Color.GREEN,
timestamp: block.timestamp
});
}
}

// Add some distinctive pixels to represent Buidlguidl spirit
canvas[32][25] = Pixel({
author: owner(),
color: Color.RED,
timestamp: block.timestamp
});
}

/**
* @dev Place a pixel on the canvas
* @param x X-coordinate of the pixel
* @param y Y-coordinate of the pixel
* @param color Color of the pixel
*/
function placePixel(uint256 x, uint256 y, Color color) external {
// Validate pixel coordinates
require(x < CANVAS_WIDTH, "X coordinate out of bounds");
require(y < CANVAS_HEIGHT, "Y coordinate out of bounds");

// Update pixel
canvas[x][y] = Pixel({
author: msg.sender,
color: color,
timestamp: block.timestamp
});

// Emit event
emit PixelPlaced(msg.sender, x, y, color);
}

/**
* @dev Get pixel information
* @param x X-coordinate of the pixel
* @param y Y-coordinate of the pixel
* @return Pixel details
*/
function getPixel(uint256 x, uint256 y) external view returns (Pixel memory) {
require(x < CANVAS_WIDTH, "X coordinate out of bounds");
require(y < CANVAS_HEIGHT, "Y coordinate out of bounds");
return canvas[x][y];
}




/**
* @dev Get canvas snapshot (useful for viewing entire canvas)
* @return Array of pixels
*/
function getCanvasSnapshot() external view returns (Pixel[CANVAS_WIDTH][CANVAS_HEIGHT] memory) {
return canvas;
}
}
52 changes: 52 additions & 0 deletions packages/hardhat/deploy/canvasOnchain.ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here it's called canvasOnChain

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check everything to be sure it's the same name everywhere

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[RESOLVED]

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ethers, network, run } from "hardhat";
import { ContractFactory } from "ethers";

async function main() {
// Get the account that will deploy the contract
const [deployer] = await ethers.getSigners();

console.log("Deploying PixelCanvas contract with the account:", deployer.address);

// Check deployer's balance
const balance = await ethers.provider.getBalance(deployer.address);
console.log("Account balance:", ethers.formatEther(balance), "ETH");

// Get the contract factory for PixelCanvas
const PixelCanvasFactory: ContractFactory = await ethers.getContractFactory("PixelCanvas");

// Deploy the contract
const pixelCanvas = await PixelCanvasFactory.deploy();

// Wait for the contract to be deployed
await pixelCanvas.waitForDeployment();

// Get the deployed contract address
const contractAddress = await pixelCanvas.getAddress();

console.log("PixelCanvas deployed to:", contractAddress);

// Verify the contract on Etherscan only on supported networks
if (network.name !== "hardhat" && network.name !== "localhost") {
console.log("Waiting for block confirmations...");
await new Promise(resolve => setTimeout(resolve, 45000)); // 45 seconds

try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: [],
});
console.log("Contract verified on Etherscan");
} catch (error) {
console.error("Verification failed:", error);
}
}
}

main()
.then(() => process.exit(0))
.catch(error => {
console.error("Deployment error:", error);
process.exit(1);
});

export default main;
5 changes: 3 additions & 2 deletions packages/hardhat/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "@typechain/hardhat";
import "hardhat-gas-reporter";
import "solidity-coverage";
import "@nomicfoundation/hardhat-verify";
import "@nomicfoundation/hardhat-network-helpers";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we need this import here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

import "hardhat-deploy";
import "hardhat-deploy-ethers";

Expand All @@ -33,7 +34,7 @@ const config: HardhatUserConfig = {
},
],
},
defaultNetwork: "localhost",
defaultNetwork: "sepolia",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually don't change this, because unwarned people might deploy to the incorrect network by mistake. When I want to deploy to another network I add the flag on the command:

yarn deploy --network sepolia

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[RESOLVED]

namedAccounts: {
deployer: {
// By default, it will take the first Hardhat account as the deployer
Expand All @@ -54,7 +55,7 @@ const config: HardhatUserConfig = {
accounts: [deployerPrivateKey],
},
sepolia: {
url: `https://rpc2.sepolia.org`,
url: `https://eth-sepolia.g.alchemy.com/v2/FIQ1qwifmra7ZqdkVHnZ2lHQAKG8j4Yd`,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a general rule, never include an API key in the code of a GitHub repository. Instead, use the .env file. Alternatively, you can use public RPCs, such as those available here: https://chainlist.org/chain/11155111.

accounts: [deployerPrivateKey],
},
arbitrum: {
Expand Down
1 change: 1 addition & 0 deletions packages/hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"check-types": "tsc --noEmit --incremental",
"compile": "hardhat compile",
"deploy": "hardhat deploy",
"deploy:canvas": "hardhat run deploy/canvasOnchain.ts --network sepolia",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need another script? Isn't the deploy script deploying everything that is on the deploy folder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will make changes to that it's when i'm having issue with the network but forget to remove it later on

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[RESOLVED]

"fork": "MAINNET_FORKING_ENABLED=true hardhat node --network hardhat --no-deploy",
"generate": "hardhat run scripts/generateAccount.ts",
"flatten": "hardhat flatten",
Expand Down
83 changes: 83 additions & 0 deletions packages/hardhat/test/CanvasOnchain.ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This filename

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[RESOLVED]

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { expect } from "chai";
import hre from "hardhat";

describe("PixelCanvas", function () {
async function deployPixelCanvas() {
const [owner, user1, user2] = await hre.ethers.getSigners();
const pixel = await hre.ethers.getContractFactory("PixelCanvas");
const Pixel = await pixel.deploy();
return { owner, user1, user2, Pixel };
}

describe("Deployment", function () {
it("Should set the correct owner", async function () {
const { owner, Pixel } = await loadFixture(deployPixelCanvas);
expect(await Pixel.owner()).to.equal(owner.address);
});

it("Should initialize canvas with predefined pixels", async function () {
// Check a few predefined pixels from initializeBuidlGuidlLogo()
const { owner, Pixel } = await loadFixture(deployPixelCanvas);
const bluePixel = await Pixel.canvas(15, 25);
expect(bluePixel.color).to.equal(4); // Blue is enum index 1
expect(bluePixel.author).to.equal(owner.address);
});
});

describe("Pixel Placement", function () {
it("Should allow placing a pixel", async function () {
const x = 10;
const y = 20;
const color = 2; // Red from enum
const { user1, Pixel } = await loadFixture(deployPixelCanvas);
// Place pixel from user1
await Pixel.connect(user1).placePixel(x, y, color);

const pixel = await Pixel.canvas(x, y);
expect(pixel.author).to.equal(user1.address);
expect(pixel.color).to.equal(color);
});

it("Should reject out-of-bounds pixel placement", async function () {
const { Pixel } = await loadFixture(deployPixelCanvas);
await expect(Pixel.placePixel(64, 10, 0)).to.be.revertedWith("X coordinate out of bounds");

await expect(Pixel.placePixel(10, 64, 0)).to.be.revertedWith("Y coordinate out of bounds");
});

it("Should emit PixelPlaced event", async function () {
const x = 30;
const y = 40;

const color = 3; // Green from enum
const { user1, Pixel } = await loadFixture(deployPixelCanvas);
await expect(Pixel.connect(user1).placePixel(x, y, color))
.to.emit(Pixel, "PixelPlaced")
.withArgs(user1.address, x, y, color);
});
});

describe("Pixel Retrieval", function () {
it("Should retrieve pixel information", async function () {
const x = 12;
const y = 15;
const color = 4; // Blue from enum
const { user1, Pixel } = await loadFixture(deployPixelCanvas);
await Pixel.connect(user1).placePixel(x, y, color);

const pixel = await Pixel.getPixel(x, y);
expect(pixel.author).to.equal(user1.address);
expect(pixel.color).to.equal(color);
});
});

describe("Canvas Snapshot", function () {
it("Should return full canvas snapshot", async function () {
const { Pixel } = await loadFixture(deployPixelCanvas);
const snapshot = await Pixel.getCanvasSnapshot();
expect(snapshot.length).to.equal(64);
expect(snapshot[0].length).to.equal(64);
});
});
});
2 changes: 1 addition & 1 deletion packages/nextjs/scaffold.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type ScaffoldConfig = {

const scaffoldConfig = {
// The networks on which your DApp is live
targetNetworks: [chains.optimism],
targetNetworks: [chains.sepolia],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you deploy BatchRegistry to sepolia as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am unable to even deploy to sepolia now the gas is high right now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[RESOLVED]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made all the changes but still having issue deploying sepolia is too high and when trying to use optimism it's giving me issue i don't understand pls can you help me to deploy it from your side


// The interval at which your front-end polls the RPC servers for new data
// it has no effect if you only target the local network (default is 4000)
Expand Down
Loading
Loading