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

upgrade onchain demo #34

Merged
merged 1 commit into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions on-chain-verification/.env.sample
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Alchemy: https://alchemy.com/?r=zU2MTQwNTU5Mzc2M
# How to export private key from Metamask: https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key

ALCHEMY_MUMBAI_URL=https://polygon-mumbai.g.alchemy.com/v2/YourAlchemyApiKey
MUMBAI_PRIVATE_KEY=YourPrivateKey
ALCHEMY_AMOY_URL=https://polygon-mumbai.g.alchemy.com/v2/YourAlchemyApiKey
AMOY_PRIVATE_KEY=YourPrivateKey
10 changes: 5 additions & 5 deletions on-chain-verification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ This tutorial uses [Hardhat](https://hardhat.org/) as a development environment
`npx hardhat compile`

4. Deploy smart contracts
`npx hardhat run --network mumbai scripts/deploy.js`
- results in x tx hash: 0xecf178144CceC09417412D66E2ecC8a2841eE228
- example contract creation: https://mumbai.polygonscan.com/address/0xecf178144ccec09417412d66e2ecc8a2841ee228
`npx hardhat run --network amoy scripts/deploy.js`
- console should log output similar to `ERC20zkAirdrop contract address: 0x365D13748BEBcDaFEE12Fa18eA653f4E168A190c` with different address.
- example contract creation: https://amoy.polygonscan.com/tx/0x1102ccb5d1e322c0bdf32d590695f3a70f7e2128061ee4325413297ff88034e8

5. Update the `ERC20VerifierAddress` variable in scripts/set-request.js with your deployed contract address

6. Run set-request to send the zk request to the smart contract
`npx hardhat run --network mumbai scripts/set-request.js`
- Successful tx means the age query has been set up: https://mumbai.polygonscan.com/tx/0x2ddb2db7b3d35cf7cdf658209b257fd2a51c49df2249bf46ede8979eb8410ffb
`npx hardhat run --network amoy scripts/set-request.js`
- Successful tx means the age query has been set up: https://amoy.polygonscan.com/tx/0x98e83a2aad5d41dc44fa03e0524848aeeabc8963ab36599fc3a0c8824d7ef722


## Claim airdrop from a frontend
Expand Down
90 changes: 47 additions & 43 deletions on-chain-verification/contracts/ERC20Verifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,58 @@ pragma solidity 0.8.20;
import {ERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol';
import {PrimitiveTypeUtils} from "@iden3/contracts/lib/PrimitiveTypeUtils.sol";
import {ICircuitValidator} from "@iden3/contracts/interfaces/ICircuitValidator.sol";
import {ZKPVerifier} from "@iden3/contracts/verifiers/ZKPVerifier.sol";
import {EmbeddedZKPVerifier} from "@iden3/contracts/verifiers/EmbeddedZKPVerifier.sol";

contract ERC20Verifier is ERC20Upgradeable, ZKPVerifier {
contract ERC20Verifier is ERC20Upgradeable, EmbeddedZKPVerifier {
uint64 public constant TRANSFER_REQUEST_ID = 1;

mapping(uint256 => address) public idToAddress;
mapping(address => uint256) public addressToId;

uint256 public TOKEN_AMOUNT_FOR_AIRDROP_PER_ID;
/// @custom:storage-location erc7201:polygonid.storage.ERC20Verifier
struct ERC20VerifierStorage {
mapping(uint256 => address) idToAddress;
mapping(address => uint256) addressToId;
uint256 TOKEN_AMOUNT_FOR_AIRDROP_PER_ID;
}

modifier beforeTransfer(address to) {
MainStorage storage s = _getMainStorage();
require(
s.proofs[to][TRANSFER_REQUEST_ID] == true,
"only identities who provided proof are allowed to receive tokens"
isProofVerified(to, TRANSFER_REQUEST_ID),
'only identities who provided proof for transfer requests are allowed to receive tokens'
);
_;
}
// keccak256(abi.encode(uint256(keccak256("polygonid.storage.ERC20Verifier")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC20VerifierStorageLocation =
0x3b1c3bd751d9cd42a3739426a271cdc235017946663d56eeaf827d70f8b77000;

function initialize(
string memory name,
string memory symbol
) public initializer {
super.__ERC20_init(name, symbol);
super.__ZKPVerifier_init(_msgSender());
TOKEN_AMOUNT_FOR_AIRDROP_PER_ID = 5 * 10 ** uint256(decimals());
function _getERC20VerifierStorage() private pure returns (ERC20VerifierStorage storage $) {
assembly {
$.slot := ERC20VerifierStorageLocation
}
}

function _beforeProofSubmit(
uint64 /* requestId */,
uint256[] memory inputs,
ICircuitValidator validator
) internal view override {
// check that challenge input is address of sender
address addr = PrimitiveTypeUtils.uint256LEToAddress(
inputs[validator.inputIndexOf("challenge")]
);
// this is linking between msg.sender and
require(
_msgSender() == addr,
"address in proof is not a sender address"
);
function initialize(string memory name, string memory symbol) public initializer {
ERC20VerifierStorage storage $ = _getERC20VerifierStorage();
super.__ERC20_init(name, symbol);
super.__EmbeddedZKPVerifier_init(_msgSender());
$.TOKEN_AMOUNT_FOR_AIRDROP_PER_ID = 5 * 10 ** uint256(decimals());
}

function _afterProofSubmit(
uint64 requestId,
uint256[] memory inputs,
ICircuitValidator validator
ICircuitValidator /* validator */
) internal override {
require(
requestId == TRANSFER_REQUEST_ID && addressToId[_msgSender()] == 0,
"proof can not be submitted more than once"
);

// get user id
uint256 id = inputs[1];
// additional check didn't get airdrop tokens before
if (idToAddress[id] == address(0) && addressToId[_msgSender()] == 0) {
super._mint(_msgSender(), TOKEN_AMOUNT_FOR_AIRDROP_PER_ID);
addressToId[_msgSender()] = id;
idToAddress[id] = _msgSender();
ERC20VerifierStorage storage $ = _getERC20VerifierStorage();
if (
requestId == TRANSFER_REQUEST_ID
) {
// if proof is given for transfer request id and it's a first time we mint tokens to sender
uint256 id = inputs[1];
if ($.idToAddress[id] == address(0) && $.addressToId[_msgSender()] == 0) {
super._mint(_msgSender(), $.TOKEN_AMOUNT_FOR_AIRDROP_PER_ID);
$.addressToId[_msgSender()] = id;
$.idToAddress[id] = _msgSender();
}
}
}

Expand All @@ -76,4 +67,17 @@ contract ERC20Verifier is ERC20Upgradeable, ZKPVerifier {
super._update(from, to, amount);
}


function getIdByAddress(address addr) public view returns (uint256) {
return _getERC20VerifierStorage().addressToId[addr];
}

function getAddressById(uint256 id) public view returns (address) {
return _getERC20VerifierStorage().idToAddress[id];
}

function getTokenAmountForAirdropPerId() public view returns (uint256) {
return _getERC20VerifierStorage().TOKEN_AMOUNT_FOR_AIRDROP_PER_ID;
}

}
10 changes: 5 additions & 5 deletions on-chain-verification/hardhat.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
require('@nomiclabs/hardhat-waffle');
require('dotenv').config();
require('@openzeppelin/hardhat-upgrades');
require('@nomicfoundation/hardhat-toolbox');

module.exports = {
solidity: "0.8.20",
networks: {
mumbai: {
chainId: 80001,
url: `${process.env.ALCHEMY_MUMBAI_URL}`,
accounts: [`0x${process.env.MUMBAI_PRIVATE_KEY}`]
amoy: {
chainId: 80002,
url: `${process.env.ALCHEMY_AMOY_URL}`,
accounts: [`0x${process.env.AMOY_PRIVATE_KEY}`]
}
}
};
Loading