> For the complete documentation index, see [llms.txt](https://notes.nomanaziz.me/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://notes.nomanaziz.me/development/blockchain/freecodecamp-course/12.-nfts-or-encoding.md).

# 12. NFTs | Encoding

### NFTs

* Stands for Non Fungible Token
  * 1 token is unique from all others
* Based on **ERC-721** standard
* Contains a TokenURI
  * Returns a JSON object that contains metadata of NFT
  * JSON contains an **image** part which contains url of the image
    * This URL can be hosted on chain or IPFS or whereever

***

### Pinata

* It is a paid service which helps us pin our NFT data
* It is centralized (not recommended)

***

### NFT.Storage

* Free storage to Pin our NFT Data
* Based on FileCoin Blockchain
* It is decentralized hence

***

### Encoding & Opcodes

* When we send a transaction, it is **compiled** down to bytecode and sent in **data** object of transaction
  * When a contract is created, its block's **to** address is **null**
* EVM reads the bytecode using a reader
  * Each alphabet in the bytecode corresponds to an **optcode instruction** like **00 means HALT**
    * More details at [evm.codes](https://evm.codes)

#### abi.encode && abi.encodePacked

* It is a globally available method of solidity

**Use Case : String Concatenation**

* It returns a byte object
* In versions **^0.8.12**, we can do `string.concat(stringA, stringB)`

```sol
contract Encoding {
	function combineStrings() public pure returns (string memory) {
		return string(abi.encodePacked("Hello", "World"));
	}
}
```

**Use Case : Others**

* Can encode anything to its binary

```sol
function encodeNumber() public pure returns(bytes memory) {
	bytes memory number = abi.encode(1);
	return number;
}

function encodeString() public pure returns(bytes memory) {
	bytes memory str = abi.encode("Hello");
	return str;
	// 00000000000000000000000x71231821289730129300000000000000000000000
}
```

* Normal encode method takes a lot of memory i.e initial zeros, hence, we use encodePacked which sorts of works like a compressor
* TypeCasting works similar but somewhat different behind the scenes

```sol
function encodeStringPacked() public pure returns(bytes memory) {
	bytes memory str = abi.encodePacked("Hello");
	return str;
	// 0x712318212897301293
}
```

#### abi.decode

* We can also **decode** stuff

```sol
function decodeString() public pure returns (string memory) {
	string memory str = abi.decode(encodeString(), (string));
	return str;
}
```

* We can also do multi decoding

```sol
function multiEncode() public pure returns (bytes memory) {
	bytes memory str = abi.encode("Hello", "World");
	return str;
}
function multiDecode() public pure returns (string memory, string memory) {
	(string memory str1, string memory str2) = abi.decode(multiEncode(), (string, string));
	return (str1, str2);
}
```

* In order to decode packed objects, we must cast

```sol
function multiEncodePacked() public pure returns(bytes memory) {
	bytes memory str = abi.encodePacked("Hello", "World");
	return str;
}

function multiStringCastPacked() public pure returns (string memory) {
	bytes memory str = string(multiEncodePacked());
	return str;
}
```

***

### Encoding Function Calls

#### call

* We use call functions to change the state of the blockchain
* In our `{}`, we are able to pass specific fields of transactions like value
* In our `()`, we can pass data to call a specific function

**Withdraw Use Case**

We used call with data field empty to send or receive ether

```sol
function withdraw(address winner) public {
	(bool success, bytes memory response) = winner.call{value: address(this).balance}("");
	require(success, string(response));
}
```

**Calling Other Functions Use Case**

We need to encode the function name and parameters down to binary level

* Each function has its function id known as **function selector**
  * It is **first 4 bytes** of the function signature
  * **Function signature** is a string that defines the function name and params

```solidity
contract CallAnything {
	address public s_someAddress;
	uint256 public s_amount;

	function transfer(address someAddress, uint256 amount) public {
		s_someAddress = someAddress;
		s_amount = amount;
	}

	function getSelectorOne() public pure returns(bytes4 selector) {
		selector = bytes4(keccak256(bytes("transfer(address,uint256)")));
	}

	function getDataToCallTransfer(address someAddress, uint256 amount) public pure returns(bytes memory) {
		return abi.encodeWithSelector(getSelectorOne(), someAddress, amount);
	}

	function callTransferFunctionDirectly(address someAddress, uint256 amount) public returns(bytes4, bool) {
		(bool success, bytes memory returnData) = address(this).call(
			getDataToCallTransfer(someAddress, amount)
		);
		return(bytes4(returnData), success);
	}
```

```sol
	function callTransferFunctionDirectlySig(address someAddress, uint256 amount) public returns(bytes4, bool) {
		(bool success, bytes memory returnData) = address(this).call(
			abi.encodeWithSignature("transfer(address,uint256)", someAddress, amount)
		);
		return(bytes4(returnData), success);
	}
}
```

#### staticcall

* We use staticcall to call our `view` or `pure` functions

***
