This week was all about understanding how multisigs and SVG NFTs work.
https://github.com/route-2/challenge-5-multisig
Learnt about meta transactions and off-chain signature-based shared wallet amongst different signers.
//generates a unique hash for each transaction,
function getTransactionHash(uint256 _nonce, address to, uint256 value, bytes memory data) public view returns (bytes32) {
return keccak256(abi.encodePacked(address(this), chainId, _nonce, to, value, data));
}
// executing a transaction
function executeTransaction(address payable to, uint256 value, bytes memory data, bytes[] memory signatures)
public
returns (bytes memory)
{
require(isOwner[msg.sender], "executeTransaction: only owners can execute");
bytes32 _hash = getTransactionHash(nonce, to, value, data);
nonce++;
uint256 validSignatures;
address duplicateGuard;
for (uint i = 0; i < signatures.length; i++) {
address recovered = recover(_hash, signatures[i]);
require(recovered > duplicateGuard, "executeTransaction: duplicate or unordered signatures");
duplicateGuard = recovered;
if(isOwner[recovered]){
validSignatures++;
}
}
Typically, we process transactions directly on-chain, but this being a shared wallet with multiple addresses, we use Off-Chain Signature-Based Multi-Sig-Wallet.
Once the packed hash(packed hash (bytes32) is a way to represent a specific function call with its parameters as a single hash value) is generated, it can be signed by one of the signers associated with the Multisig wallet. This signature serves as a proof that the signer has authorised the execution of the corresponding function call with the specified parameters. The signature is then added to an array of signatures (bytes[] memory signatures), which contains all the signatures collected so far for the current transaction.
The user first creates a transaction that contains the necessary function call data and other parameters to carry out the desired action on the blockchain in to execute a meta transaction with an off-chain multisig wallet. The transaction is then encoded using a particular encoding technique, such as abi.encodePacked, into a packed hash (bytes32).
This packed hash is then signed by one of the signers associated with the multisig wallet using their private key. The signature is added to an array of signatures (bytes[] memory signatures), which is passed on along with the packed hash.
//Off-Chain code for getting the TX
const getSortedSigList = async (allSigs, newHash) => {
console.log("allSigs", allSigs);
const sigList = [];
for (const s in allSigs) {
console.log("SIG", allSigs[s]);
const recover = await readContracts[contractName].recover(newHash, allSigs[s]);
sigList.push({ signature: allSigs[s], signer: recover });
}
sigList.sort((a, b) => {
return ethers.BigNumber.from(a.signer).sub(ethers.BigNumber.from(b.signer));
});
The smart contract that receives the transaction validates the signatures in the array to ensure that they match the signers' public keys associated with the multisig wallet. If the signatures are valid, the transaction is carried out on the blockchain as the user requested.
https://github.com/route-2/challenge-7-svg
This challenge was about creating On-Chain SVG NFTs, most of the NFTs are usually IPFS hosted i.e, only the link is stored on blockchain and the metadata is stored on IPFS.
We can see this by querying the NFT contract's tokenURI. The data in SVG NFTs is stored entirely on-chain, directly in the smart contract. Instead of a link, the tokenURI returns encoded json data that includes SVG data that can be displayed in a browser.
SVG NFTs are also seen in projects like the Bored Ape Yacht Club which uses SVG NFTs to represent unique digital apes that have become highly popular collectibles,Gaming projects, such as Axie Infinity uses SVG NFTs to represent unique in-game creatures, Digital music-related SVG NFTs,Uniswap has launched LP as SVG NFTs in v3 implementation as well.
// SVG NFT data which is dynamic as the trait type 'color' and 'chubbiness' changes
function tokenURI(uint256 id) public view override returns (string memory) {
require(_exists(id), "not exist");
string memory name = string(abi.encodePacked('Loogie #',id.toString()));
string memory description = string(abi.encodePacked('This Loogie is the color #',color[id].toColor(),' with a chubbiness of ',uint2str(chubbiness[id]),'!!!'));
string memory image = Base64.encode(bytes(generateSVGofTokenById(id)));
return
string(
abi.encodePacked(
'data:application/json;base64,',
Base64.encode(
bytes(
abi.encodePacked(
'{"name":"',
name,
'", "description":"',
description,
'", "external_url":"https://burnyboys.com/token/',
id.toString(),
'", "attributes": [{"trait_type": "color", "value": "#',
color[id].toColor(),
'"},{"trait_type": "chubbiness", "value": ',
uint2str(chubbiness[id]),
'}], "owner":"',
(uint160(ownerOf(id))).toHexString(20),
'", "image": "',
'data:image/svg+xml;base64,',
image,
'"}'
)
)
)
)
);
}
This allows you to generate SVGs
function generateSVGofTokenById(uint256 id) internal view returns (string memory) {
string memory svg = string(abi.encodePacked(
'<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">',
renderTokenById(id),
'</svg>'
));
return svg;
}
That’s about it thank you you’ve reached the end :) Subscribe to get notified
This week was all about understanding how multisigs and SVG NFTs work.
https://github.com/route-2/challenge-5-multisig
Learnt about meta transactions and off-chain signature-based shared wallet amongst different signers.
//generates a unique hash for each transaction,
function getTransactionHash(uint256 _nonce, address to, uint256 value, bytes memory data) public view returns (bytes32) {
return keccak256(abi.encodePacked(address(this), chainId, _nonce, to, value, data));
}
// executing a transaction
function executeTransaction(address payable to, uint256 value, bytes memory data, bytes[] memory signatures)
public
returns (bytes memory)
{
require(isOwner[msg.sender], "executeTransaction: only owners can execute");
bytes32 _hash = getTransactionHash(nonce, to, value, data);
nonce++;
uint256 validSignatures;
address duplicateGuard;
for (uint i = 0; i < signatures.length; i++) {
address recovered = recover(_hash, signatures[i]);
require(recovered > duplicateGuard, "executeTransaction: duplicate or unordered signatures");
duplicateGuard = recovered;
if(isOwner[recovered]){
validSignatures++;
}
}
Typically, we process transactions directly on-chain, but this being a shared wallet with multiple addresses, we use Off-Chain Signature-Based Multi-Sig-Wallet.
Once the packed hash(packed hash (bytes32) is a way to represent a specific function call with its parameters as a single hash value) is generated, it can be signed by one of the signers associated with the Multisig wallet. This signature serves as a proof that the signer has authorised the execution of the corresponding function call with the specified parameters. The signature is then added to an array of signatures (bytes[] memory signatures), which contains all the signatures collected so far for the current transaction.
The user first creates a transaction that contains the necessary function call data and other parameters to carry out the desired action on the blockchain in to execute a meta transaction with an off-chain multisig wallet. The transaction is then encoded using a particular encoding technique, such as abi.encodePacked, into a packed hash (bytes32).
This packed hash is then signed by one of the signers associated with the multisig wallet using their private key. The signature is added to an array of signatures (bytes[] memory signatures), which is passed on along with the packed hash.
//Off-Chain code for getting the TX
const getSortedSigList = async (allSigs, newHash) => {
console.log("allSigs", allSigs);
const sigList = [];
for (const s in allSigs) {
console.log("SIG", allSigs[s]);
const recover = await readContracts[contractName].recover(newHash, allSigs[s]);
sigList.push({ signature: allSigs[s], signer: recover });
}
sigList.sort((a, b) => {
return ethers.BigNumber.from(a.signer).sub(ethers.BigNumber.from(b.signer));
});
The smart contract that receives the transaction validates the signatures in the array to ensure that they match the signers' public keys associated with the multisig wallet. If the signatures are valid, the transaction is carried out on the blockchain as the user requested.
https://github.com/route-2/challenge-7-svg
This challenge was about creating On-Chain SVG NFTs, most of the NFTs are usually IPFS hosted i.e, only the link is stored on blockchain and the metadata is stored on IPFS.
We can see this by querying the NFT contract's tokenURI. The data in SVG NFTs is stored entirely on-chain, directly in the smart contract. Instead of a link, the tokenURI returns encoded json data that includes SVG data that can be displayed in a browser.
SVG NFTs are also seen in projects like the Bored Ape Yacht Club which uses SVG NFTs to represent unique digital apes that have become highly popular collectibles,Gaming projects, such as Axie Infinity uses SVG NFTs to represent unique in-game creatures, Digital music-related SVG NFTs,Uniswap has launched LP as SVG NFTs in v3 implementation as well.
// SVG NFT data which is dynamic as the trait type 'color' and 'chubbiness' changes
function tokenURI(uint256 id) public view override returns (string memory) {
require(_exists(id), "not exist");
string memory name = string(abi.encodePacked('Loogie #',id.toString()));
string memory description = string(abi.encodePacked('This Loogie is the color #',color[id].toColor(),' with a chubbiness of ',uint2str(chubbiness[id]),'!!!'));
string memory image = Base64.encode(bytes(generateSVGofTokenById(id)));
return
string(
abi.encodePacked(
'data:application/json;base64,',
Base64.encode(
bytes(
abi.encodePacked(
'{"name":"',
name,
'", "description":"',
description,
'", "external_url":"https://burnyboys.com/token/',
id.toString(),
'", "attributes": [{"trait_type": "color", "value": "#',
color[id].toColor(),
'"},{"trait_type": "chubbiness", "value": ',
uint2str(chubbiness[id]),
'}], "owner":"',
(uint160(ownerOf(id))).toHexString(20),
'", "image": "',
'data:image/svg+xml;base64,',
image,
'"}'
)
)
)
)
);
}
This allows you to generate SVGs
function generateSVGofTokenById(uint256 id) internal view returns (string memory) {
string memory svg = string(abi.encodePacked(
'<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">',
renderTokenById(id),
'</svg>'
));
return svg;
}
That’s about it thank you you’ve reached the end :) Subscribe to get notified
<100 subscribers
<100 subscribers
Share Dialog
Share Dialog
Ruthu Rao
Ruthu Rao
No comments yet