diff --git a/src/.vuepress/config/sidebar-pt.js b/src/.vuepress/config/sidebar-pt.js
index 8419cb1..d7d0af4 100644
--- a/src/.vuepress/config/sidebar-pt.js
+++ b/src/.vuepress/config/sidebar-pt.js
@@ -88,24 +88,36 @@ module.exports = [
"/exemplos/linguagem-v0.8.3/import.md",
"/exemplos/linguagem-v0.8.3/biblioteca.md",
"/exemplos/linguagem-v0.8.3/hashing-with-keccak256.md",
- "/exemplos/linguagem-v0.8.3/verificando-assinatura.md"
+ "/exemplos/linguagem-v0.8.3/verificando-assinatura.md",
],
},
{
title: "Aplicações",
path: "/exemplos/aplicacoes/",
children: [
+ "/exemplos/aplicacoes/carteira-ether.md",
"/exemplos/aplicacoes/carteira-multi-assinaturas.md",
"/exemplos/aplicacoes/arvore-de-merkle.md",
"/exemplos/aplicacoes/mapping-iteravel",
"/exemplos/aplicacoes/erc20.md",
+ "/exemplos/aplicacoes/erc721.md",
+ "/exemplos/aplicacoes/erc1155.md",
+ "/exemplos/aplicacoes/transferencia-de-token-sem-gas.md",
+ "/exemplos/aplicacoes/contrato-de-bytecode-simples.md",
"/exemplos/aplicacoes/endereco-de-contrato-pre-computado-com-create2.md",
"/exemplos/aplicacoes/contrato-proxy-minimo.md",
+ "/exemplos/aplicacoes/proxy-atualizavel.md",
"/exemplos/aplicacoes/implante-qualquer-contrato.md",
+ "/exemplos/aplicacoes/gravar-em-qualquer-slot.md",
"/exemplos/aplicacoes/canal-de-pagamento-unidirecional.md",
"/exemplos/aplicacoes/canal-de-pagamento-bidirecional.md",
"/exemplos/aplicacoes/leilao-ingles.md",
"/exemplos/aplicacoes/leilao-holandes.md",
+ "/exemplos/aplicacoes/vaquinha.md",
+ "/exemplos/aplicacoes/multi-chamadas.md",
+ "/exemplos/aplicacoes/multi-delegatecall.md",
+ "/exemplos/aplicacoes/bloqueio-de-tempo.md",
+ "/exemplos/aplicacoes/exponenciacao-binaria-em-assembly.md",
],
},
{
@@ -153,7 +165,9 @@ module.exports = [
{
title: "Patterns and Standards",
path: "/evm-maquina-virtual-ethereum/patterns-and-standards",
- children: ["/evm-maquina-virtual-ethereum/patterns-and-standards/erc20-and-eip-20.md"],
+ children: [
+ "/evm-maquina-virtual-ethereum/patterns-and-standards/erc20-and-eip-20.md",
+ ],
},
],
},
@@ -171,4 +185,4 @@ module.exports = [
},
],
},
-]
+];
diff --git a/src/exemplos/aplicacoes/arvore-de-merkle.md b/src/exemplos/aplicacoes/arvore-de-merkle.md
index 30888b7..855b623 100644
--- a/src/exemplos/aplicacoes/arvore-de-merkle.md
+++ b/src/exemplos/aplicacoes/arvore-de-merkle.md
@@ -1,12 +1,10 @@
# Árvore de Merkle
-A árvore de Merkle te permite provar criptograficamente que um elemento está contido
-
-num conjunto sem revelar o conjunto inteiro.
+A árvore de Merkle permite você provar criptograficamente que um elemento está contido num conjunto sem revelar o conjunto inteiro.
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
contract MerkleProof {
function verify(
@@ -70,17 +68,21 @@ contract TestMerkleProof is MerkleProof {
/* verifica
3rd leaf
- 0x1bbd78ae6188015c4a6772eb1526292b5985fc3272ead4c65002240fb9ae5d13
+ 0xdca3326ad7e8121bf9cf9c12333e6b2271abe823ec9edfe42f813b1e768fa57b
- raiz
- 0x074b43252ffb4a469154df5fb7fe4ecce30953ba8b7095fe1e006185f017ad10
+ root
+ 0xcc086fcc038189b4641db2cc4f1de3bb132aefbd65d510d817591550937818c7
index
2
prova
- 0x948f90037b4ea787c14540d9feb1034d4a5bc251b9b5f8e57d81e4b470027af8
- 0x63ac1b92046d474f84be3aa0ee04ffe5600862228c81803cce07ac40484aee43
+ 0x8da9e1c820f9dbd1589fd6585872bc1063588625729e7ab0797cfc63a00bd950
+ 0x995788ffc103b987ad50f5e5707fd094419eb12d9552cc423bd0cd86a3861433
*/
}
```
+
+## Teste no Remix
+
+- [MerkleProof.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IE1lcmtsZVByb29mIHsKICAgIGZ1bmN0aW9uIHZlcmlmeSgKICAgICAgICBieXRlczMyW10gbWVtb3J5IHByb29mLAogICAgICAgIGJ5dGVzMzIgcm9vdCwKICAgICAgICBieXRlczMyIGxlYWYsCiAgICAgICAgdWludCBpbmRleAogICAgKSBwdWJsaWMgcHVyZSByZXR1cm5zIChib29sKSB7CiAgICAgICAgYnl0ZXMzMiBoYXNoID0gbGVhZjsKCiAgICAgICAgZm9yICh1aW50IGkgPSAwOyBpIDwgcHJvb2YubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgYnl0ZXMzMiBwcm9vZkVsZW1lbnQgPSBwcm9vZltpXTsKCiAgICAgICAgICAgIGlmIChpbmRleCAlIDIgPT0gMCkgewogICAgICAgICAgICAgICAgaGFzaCA9IGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKGhhc2gsIHByb29mRWxlbWVudCkpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgaGFzaCA9IGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKHByb29mRWxlbWVudCwgaGFzaCkpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBpbmRleCA9IGluZGV4IC8gMjsKICAgICAgICB9CgogICAgICAgIHJldHVybiBoYXNoID09IHJvb3Q7CiAgICB9Cn0KCmNvbnRyYWN0IFRlc3RNZXJrbGVQcm9vZiBpcyBNZXJrbGVQcm9vZiB7CiAgICBieXRlczMyW10gcHVibGljIGhhc2hlczsKCiAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICBzdHJpbmdbNF0gbWVtb3J5IHRyYW5zYWN0aW9ucyA9IFsKICAgICAgICAgICAiYWxpY2UgLT4gYm9iIiwKICAgICAgICAgICAiYm9iIC0+IGRhdmUiLAogICAgICAgICAgICJjYXJvbCAtPiBhbGljZSIsCiAgICAgICAgICAgImRhdmUgLT4gYm9iIgogICAgICAgIF07CgogICAgICAgIGZvciAodWludCBpID0gMDsgaSA8IHRyYW5zYWN0aW9ucy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICBoYXNoZXMucHVzaChrZWNjYWsyNTYoYWJpLmVuY29kZVBhY2tlZCh0cmFuc2FjdGlvbnNbaV0pKSk7CiAgICAgICAgfQoKICAgICAgICB1aW50IG4gPSB0cmFuc2FjdGlvbnMubGVuZ3RoOwogICAgICAgIHVpbnQgb2Zmc2V0ID0gMDsKCiAgICAgICAgd2hpbGUgKG4gPiAwKSB7CiAgICAgICAgICAgIGZvciAodWludCBpID0gMDsgaSA8IG4gLSAxOyBpICs9IDIpIHsKICAgICAgICAgICAgICAgIGhhc2hlcy5wdXNoKAogICAgICAgICAgICAgICAgICAgIGtlY2NhazI1NigKICAgICAgICAgICAgICAgICAgICAgICAgYWJpLmVuY29kZVBhY2tlZChoYXNoZXNbb2Zmc2V0ICsgaV0sIGhhc2hlc1tvZmZzZXQgKyBpICsgMV0pCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBvZmZzZXQgKz0gbjsKICAgICAgICAgICAgbiA9IG4gLyAyOwogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBnZXRSb290KCkgcHVibGljIHZpZXcgcmV0dXJucyAoYnl0ZXMzMikgewogICAgICAgIHJldHVybiBoYXNoZXNbaGFzaGVzLmxlbmd0aCAtIDFdOwogICAgfQoKICAgIC8qIHZlcmlmaWNhCiAgICAzcmQgbGVhZgogICAgMHhkY2EzMzI2YWQ3ZTgxMjFiZjljZjljMTIzMzNlNmIyMjcxYWJlODIzZWM5ZWRmZTQyZjgxM2IxZTc2OGZhNTdiCgogICAgcm9vdAogICAgMHhjYzA4NmZjYzAzODE4OWI0NjQxZGIyY2M0ZjFkZTNiYjEzMmFlZmJkNjVkNTEwZDgxNzU5MTU1MDkzNzgxOGM3CgogICAgaW5kZXgKICAgIDIKCiAgICBwcm92YQogICAgMHg4ZGE5ZTFjODIwZjlkYmQxNTg5ZmQ2NTg1ODcyYmMxMDYzNTg4NjI1NzI5ZTdhYjA3OTdjZmM2M2EwMGJkOTUwCiAgICAweDk5NTc4OGZmYzEwM2I5ODdhZDUwZjVlNTcwN2ZkMDk0NDE5ZWIxMmQ5NTUyY2M0MjNiZDBjZDg2YTM4NjE0MzMKICAgICovCn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/bloqueio-de-tempo.md b/src/exemplos/aplicacoes/bloqueio-de-tempo.md
new file mode 100644
index 0000000..e7a50d8
--- /dev/null
+++ b/src/exemplos/aplicacoes/bloqueio-de-tempo.md
@@ -0,0 +1,158 @@
+# Bloqueio de tempo
+
+`TimeLock` é um contrato que publica uma transação a ser executada no futuro. Após um período de espera mínimo, a transação pode ser executada.
+
+`TimeLocks` são comumente usados em DAOs.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+contract TimeLock {
+ error NotOwnerError();
+ error AlreadyQueuedError(bytes32 txId);
+ error TimestampNotInRangeError(uint blockTimestamp, uint timestamp);
+ error NotQueuedError(bytes32 txId);
+ error TimestampNotPassedError(uint blockTimestmap, uint timestamp);
+ error TimestampExpiredError(uint blockTimestamp, uint expiresAt);
+ error TxFailedError();
+
+ event Queue(
+ bytes32 indexed txId,
+ address indexed target,
+ uint value,
+ string func,
+ bytes data,
+ uint timestamp
+ );
+ event Execute(
+ bytes32 indexed txId,
+ address indexed target,
+ uint value,
+ string func,
+ bytes data,
+ uint timestamp
+ );
+ event Cancel(bytes32 indexed txId);
+
+ uint public constant MIN_DELAY = 10; // segundos
+ uint public constant MAX_DELAY = 1000; // segundos
+ uint public constant GRACE_PERIOD = 1000; // segundos
+
+ address public owner;
+ // tx id => queued
+ mapping(bytes32 => bool) public queued;
+
+ constructor() {
+ owner = msg.sender;
+ }
+
+ modifier onlyOwner() {
+ if (msg.sender != owner) {
+ revert NotOwnerError();
+ }
+ _;
+ }
+
+ receive() external payable {}
+
+ function getTxId(
+ address _target,
+ uint _value,
+ string calldata _func,
+ bytes calldata _data,
+ uint _timestamp
+ ) public pure returns (bytes32) {
+ return keccak256(abi.encode(_target, _value, _func, _data, _timestamp));
+ }
+
+ /**
+ * @param _target Address of contract or account to call
+ * @param _value Amount of ETH to send
+ * @param _func Function signature, for example "foo(address,uint256)"
+ * @param _data ABI encoded data send.
+ * @param _timestamp Timestamp after which the transaction can be executed.
+ */
+ function queue(
+ address _target,
+ uint _value,
+ string calldata _func,
+ bytes calldata _data,
+ uint _timestamp
+ ) external onlyOwner returns (bytes32 txId) {
+ txId = getTxId(_target, _value, _func, _data, _timestamp);
+ if (queued[txId]) {
+ revert AlreadyQueuedError(txId);
+ }
+ // ---|------------|---------------|-------
+ // block block + min block + max
+ if (
+ _timestamp < block.timestamp + MIN_DELAY ||
+ _timestamp > block.timestamp + MAX_DELAY
+ ) {
+ revert TimestampNotInRangeError(block.timestamp, _timestamp);
+ }
+
+ queued[txId] = true;
+
+ emit Queue(txId, _target, _value, _func, _data, _timestamp);
+ }
+
+ function execute(
+ address _target,
+ uint _value,
+ string calldata _func,
+ bytes calldata _data,
+ uint _timestamp
+ ) external payable onlyOwner returns (bytes memory) {
+ bytes32 txId = getTxId(_target, _value, _func, _data, _timestamp);
+ if (!queued[txId]) {
+ revert NotQueuedError(txId);
+ }
+ // ----|-------------------|-------
+ // timestamp timestamp + período de carência
+ if (block.timestamp < _timestamp) {
+ revert TimestampNotPassedError(block.timestamp, _timestamp);
+ }
+ if (block.timestamp > _timestamp + GRACE_PERIOD) {
+ revert TimestampExpiredError(block.timestamp, _timestamp + GRACE_PERIOD);
+ }
+
+ queued[txId] = false;
+
+ // preparar dados
+ bytes memory data;
+ if (bytes(_func).length > 0) {
+ // data = func selector + _data
+ data = abi.encodePacked(bytes4(keccak256(bytes(_func))), _data);
+ } else {
+ // chamada de fallback com dados
+ data = _data;
+ }
+
+ // alvo de chamada
+ (bool ok, bytes memory res) = _target.call{value: _value}(data);
+ if (!ok) {
+ revert TxFailedError();
+ }
+
+ emit Execute(txId, _target, _value, _func, _data, _timestamp);
+
+ return res;
+ }
+
+ function cancel(bytes32 _txId) external onlyOwner {
+ if (!queued[_txId]) {
+ revert NotQueuedError(_txId);
+ }
+
+ queued[_txId] = false;
+
+ emit Cancel(_txId);
+ }
+}
+```
+
+## Teste no Remix
+
+- [TimeLock.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IFRpbWVMb2NrIHsKICAgIGVycm9yIE5vdE93bmVyRXJyb3IoKTsKICAgIGVycm9yIEFscmVhZHlRdWV1ZWRFcnJvcihieXRlczMyIHR4SWQpOwogICAgZXJyb3IgVGltZXN0YW1wTm90SW5SYW5nZUVycm9yKHVpbnQgYmxvY2tUaW1lc3RhbXAsIHVpbnQgdGltZXN0YW1wKTsKICAgIGVycm9yIE5vdFF1ZXVlZEVycm9yKGJ5dGVzMzIgdHhJZCk7CiAgICBlcnJvciBUaW1lc3RhbXBOb3RQYXNzZWRFcnJvcih1aW50IGJsb2NrVGltZXN0bWFwLCB1aW50IHRpbWVzdGFtcCk7CiAgICBlcnJvciBUaW1lc3RhbXBFeHBpcmVkRXJyb3IodWludCBibG9ja1RpbWVzdGFtcCwgdWludCBleHBpcmVzQXQpOwogICAgZXJyb3IgVHhGYWlsZWRFcnJvcigpOwoKICAgIGV2ZW50IFF1ZXVlKAogICAgICAgIGJ5dGVzMzIgaW5kZXhlZCB0eElkLAogICAgICAgIGFkZHJlc3MgaW5kZXhlZCB0YXJnZXQsCiAgICAgICAgdWludCB2YWx1ZSwKICAgICAgICBzdHJpbmcgZnVuYywKICAgICAgICBieXRlcyBkYXRhLAogICAgICAgIHVpbnQgdGltZXN0YW1wCiAgICApOwogICAgZXZlbnQgRXhlY3V0ZSgKICAgICAgICBieXRlczMyIGluZGV4ZWQgdHhJZCwKICAgICAgICBhZGRyZXNzIGluZGV4ZWQgdGFyZ2V0LAogICAgICAgIHVpbnQgdmFsdWUsCiAgICAgICAgc3RyaW5nIGZ1bmMsCiAgICAgICAgYnl0ZXMgZGF0YSwKICAgICAgICB1aW50IHRpbWVzdGFtcAogICAgKTsKICAgIGV2ZW50IENhbmNlbChieXRlczMyIGluZGV4ZWQgdHhJZCk7CgogICAgdWludCBwdWJsaWMgY29uc3RhbnQgTUlOX0RFTEFZID0gMTA7IC8vIHNlZ3VuZG9zCiAgICB1aW50IHB1YmxpYyBjb25zdGFudCBNQVhfREVMQVkgPSAxMDAwOyAvLyBzZWd1bmRvcwogICAgdWludCBwdWJsaWMgY29uc3RhbnQgR1JBQ0VfUEVSSU9EID0gMTAwMDsgLy8gc2VndW5kb3MKCiAgICBhZGRyZXNzIHB1YmxpYyBvd25lcjsKICAgIC8vIHR4IGlkID0+IHF1ZXVlZAogICAgbWFwcGluZyhieXRlczMyID0+IGJvb2wpIHB1YmxpYyBxdWV1ZWQ7CgogICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgb3duZXIgPSBtc2cuc2VuZGVyOwogICAgfQoKICAgIG1vZGlmaWVyIG9ubHlPd25lcigpIHsKICAgICAgICBpZiAobXNnLnNlbmRlciAhPSBvd25lcikgewogICAgICAgICAgICByZXZlcnQgTm90T3duZXJFcnJvcigpOwogICAgICAgIH0KICAgICAgICBfOwogICAgfQoKICAgIHJlY2VpdmUoKSBleHRlcm5hbCBwYXlhYmxlIHt9CgogICAgZnVuY3Rpb24gZ2V0VHhJZCgKICAgICAgICBhZGRyZXNzIF90YXJnZXQsCiAgICAgICAgdWludCBfdmFsdWUsCiAgICAgICAgc3RyaW5nIGNhbGxkYXRhIF9mdW5jLAogICAgICAgIGJ5dGVzIGNhbGxkYXRhIF9kYXRhLAogICAgICAgIHVpbnQgX3RpbWVzdGFtcAogICAgKSBwdWJsaWMgcHVyZSByZXR1cm5zIChieXRlczMyKSB7CiAgICAgICAgcmV0dXJuIGtlY2NhazI1NihhYmkuZW5jb2RlKF90YXJnZXQsIF92YWx1ZSwgX2Z1bmMsIF9kYXRhLCBfdGltZXN0YW1wKSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAcGFyYW0gX3RhcmdldCBBZGRyZXNzIG9mIGNvbnRyYWN0IG9yIGFjY291bnQgdG8gY2FsbAogICAgICogQHBhcmFtIF92YWx1ZSBBbW91bnQgb2YgRVRIIHRvIHNlbmQKICAgICAqIEBwYXJhbSBfZnVuYyBGdW5jdGlvbiBzaWduYXR1cmUsIGZvciBleGFtcGxlICJmb28oYWRkcmVzcyx1aW50MjU2KSIKICAgICAqIEBwYXJhbSBfZGF0YSBBQkkgZW5jb2RlZCBkYXRhIHNlbmQuCiAgICAgKiBAcGFyYW0gX3RpbWVzdGFtcCBUaW1lc3RhbXAgYWZ0ZXIgd2hpY2ggdGhlIHRyYW5zYWN0aW9uIGNhbiBiZSBleGVjdXRlZC4KICAgICAqLwogICAgZnVuY3Rpb24gcXVldWUoCiAgICAgICAgYWRkcmVzcyBfdGFyZ2V0LAogICAgICAgIHVpbnQgX3ZhbHVlLAogICAgICAgIHN0cmluZyBjYWxsZGF0YSBfZnVuYywKICAgICAgICBieXRlcyBjYWxsZGF0YSBfZGF0YSwKICAgICAgICB1aW50IF90aW1lc3RhbXAKICAgICkgZXh0ZXJuYWwgb25seU93bmVyIHJldHVybnMgKGJ5dGVzMzIgdHhJZCkgewogICAgICAgIHR4SWQgPSBnZXRUeElkKF90YXJnZXQsIF92YWx1ZSwgX2Z1bmMsIF9kYXRhLCBfdGltZXN0YW1wKTsKICAgICAgICBpZiAocXVldWVkW3R4SWRdKSB7CiAgICAgICAgICAgIHJldmVydCBBbHJlYWR5UXVldWVkRXJyb3IodHhJZCk7CiAgICAgICAgfQogICAgICAgIC8vIC0tLXwtLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0KICAgICAgICAvLyAgYmxvY2sgICAgYmxvY2sgKyBtaW4gICAgIGJsb2NrICsgbWF4CiAgICAgICAgaWYgKAogICAgICAgICAgICBfdGltZXN0YW1wIDwgYmxvY2sudGltZXN0YW1wICsgTUlOX0RFTEFZIHx8CiAgICAgICAgICAgIF90aW1lc3RhbXAgPiBibG9jay50aW1lc3RhbXAgKyBNQVhfREVMQVkKICAgICAgICApIHsKICAgICAgICAgICAgcmV2ZXJ0IFRpbWVzdGFtcE5vdEluUmFuZ2VFcnJvcihibG9jay50aW1lc3RhbXAsIF90aW1lc3RhbXApOwogICAgICAgIH0KCiAgICAgICAgcXVldWVkW3R4SWRdID0gdHJ1ZTsKCiAgICAgICAgZW1pdCBRdWV1ZSh0eElkLCBfdGFyZ2V0LCBfdmFsdWUsIF9mdW5jLCBfZGF0YSwgX3RpbWVzdGFtcCk7CiAgICB9CgogICAgZnVuY3Rpb24gZXhlY3V0ZSgKICAgICAgICBhZGRyZXNzIF90YXJnZXQsCiAgICAgICAgdWludCBfdmFsdWUsCiAgICAgICAgc3RyaW5nIGNhbGxkYXRhIF9mdW5jLAogICAgICAgIGJ5dGVzIGNhbGxkYXRhIF9kYXRhLAogICAgICAgIHVpbnQgX3RpbWVzdGFtcAogICAgKSBleHRlcm5hbCBwYXlhYmxlIG9ubHlPd25lciByZXR1cm5zIChieXRlcyBtZW1vcnkpIHsKICAgICAgICBieXRlczMyIHR4SWQgPSBnZXRUeElkKF90YXJnZXQsIF92YWx1ZSwgX2Z1bmMsIF9kYXRhLCBfdGltZXN0YW1wKTsKICAgICAgICBpZiAoIXF1ZXVlZFt0eElkXSkgewogICAgICAgICAgICByZXZlcnQgTm90UXVldWVkRXJyb3IodHhJZCk7CiAgICAgICAgfQogICAgICAgIC8vIC0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tCiAgICAgICAgLy8gIHRpbWVzdGFtcCAgICB0aW1lc3RhbXAgKyBwZXJpb2RvIGRlIGNhcmVuY2lhCiAgICAgICAgaWYgKGJsb2NrLnRpbWVzdGFtcCA8IF90aW1lc3RhbXApIHsKICAgICAgICAgICAgcmV2ZXJ0IFRpbWVzdGFtcE5vdFBhc3NlZEVycm9yKGJsb2NrLnRpbWVzdGFtcCwgX3RpbWVzdGFtcCk7CiAgICAgICAgfQogICAgICAgIGlmIChibG9jay50aW1lc3RhbXAgPiBfdGltZXN0YW1wICsgR1JBQ0VfUEVSSU9EKSB7CiAgICAgICAgICAgIHJldmVydCBUaW1lc3RhbXBFeHBpcmVkRXJyb3IoYmxvY2sudGltZXN0YW1wLCBfdGltZXN0YW1wICsgR1JBQ0VfUEVSSU9EKTsKICAgICAgICB9CgogICAgICAgIHF1ZXVlZFt0eElkXSA9IGZhbHNlOwoKICAgICAgICAvLyBwcmVwYXJhciBkYWRvcwogICAgICAgIGJ5dGVzIG1lbW9yeSBkYXRhOwogICAgICAgIGlmIChieXRlcyhfZnVuYykubGVuZ3RoID4gMCkgewogICAgICAgICAgICAvLyBkYXRhID0gZnVuYyBzZWxlY3RvciArIF9kYXRhCiAgICAgICAgICAgIGRhdGEgPSBhYmkuZW5jb2RlUGFja2VkKGJ5dGVzNChrZWNjYWsyNTYoYnl0ZXMoX2Z1bmMpKSksIF9kYXRhKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAvLyBjaGFtYWRhIGRlIGZhbGxiYWNrIGNvbSBkYWRvcwogICAgICAgICAgICBkYXRhID0gX2RhdGE7CiAgICAgICAgfQoKICAgICAgICAvLyBhbHZvIGRlIGNoYW1hZGEKICAgICAgICAoYm9vbCBvaywgYnl0ZXMgbWVtb3J5IHJlcykgPSBfdGFyZ2V0LmNhbGx7dmFsdWU6IF92YWx1ZX0oZGF0YSk7CiAgICAgICAgaWYgKCFvaykgewogICAgICAgICAgICByZXZlcnQgVHhGYWlsZWRFcnJvcigpOwogICAgICAgIH0KCiAgICAgICAgZW1pdCBFeGVjdXRlKHR4SWQsIF90YXJnZXQsIF92YWx1ZSwgX2Z1bmMsIF9kYXRhLCBfdGltZXN0YW1wKTsKCiAgICAgICAgcmV0dXJuIHJlczsKICAgIH0KCiAgICBmdW5jdGlvbiBjYW5jZWwoYnl0ZXMzMiBfdHhJZCkgZXh0ZXJuYWwgb25seU93bmVyIHsKICAgICAgICBpZiAoIXF1ZXVlZFtfdHhJZF0pIHsKICAgICAgICAgICAgcmV2ZXJ0IE5vdFF1ZXVlZEVycm9yKF90eElkKTsKICAgICAgICB9CgogICAgICAgIHF1ZXVlZFtfdHhJZF0gPSBmYWxzZTsKCiAgICAgICAgZW1pdCBDYW5jZWwoX3R4SWQpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/canal-de-pagamento-bidirecional.md b/src/exemplos/aplicacoes/canal-de-pagamento-bidirecional.md
index 200e693..0dec0bc 100644
--- a/src/exemplos/aplicacoes/canal-de-pagamento-bidirecional.md
+++ b/src/exemplos/aplicacoes/canal-de-pagamento-bidirecional.md
@@ -1,13 +1,12 @@
# Canal de Pagamento Bidirecional
-Canais de pagamento bidirecional permite que os participantes `Alice` e `Bob` transfiram Ether off chain repetidamente.
+Canais de pagamento bidirecional permite que os participantes `Alice` e `Bob` transfiram Ether off chain repetidamente.
Pagamentos podem ser feitos em ambas direções, `Alice` paga `Bob` e `Bob` paga `Alice`.
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
-pragma experimental ABIEncoderV2;
+pragma solidity ^0.8.20;
/*
Abrindo um canal
@@ -20,7 +19,7 @@ Atualizar saldos do canal
1. Repete os passos 1 - 3 da abertura do canal
2. Da carteira multi-sig cria uma transação que vai
- apagar a transação que teria implementado o canal de pagamento antigo
- - e depois cria a transação que pode implementar um canal de pagamento
+ - e depois cria a transação que pode implementar um canal de pagamento
com novos balanços
Fechando um canal quando Alice e Bob concordam com o saldo final
@@ -34,11 +33,9 @@ Fechando um canal quando Alice e Bob não concordam com os saldos finais
3. Alice e Bob podem retirar fundos uma vez que o canal é extinto
*/
-import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/math/SafeMath.sol";
-import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol";
+import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol";
contract BiDirectionalPaymentChannel {
- using SafeMath for uint;
using ECDSA for bytes32;
event ChallengeExit(address indexed sender, uint nonce);
@@ -55,7 +52,7 @@ contract BiDirectionalPaymentChannel {
modifier checkBalances(uint[2] memory _balances) {
require(
- address(this).balance >= _balances[0].add(_balances[1]),
+ address(this).balance >= _balances[0] + _balances[1],
"balance of contract must be >= to the total balance of users"
);
_;
@@ -115,7 +112,7 @@ contract BiDirectionalPaymentChannel {
uint[2] memory _balances,
uint _nonce
) {
- // Nota: copia a matriz de armazenamento para a memória
+ // Note: copy storage array to memory
address[2] memory signers;
for (uint i = 0; i < users.length; i++) {
signers[i] = users[i];
@@ -152,7 +149,7 @@ contract BiDirectionalPaymentChannel {
}
nonce = _nonce;
- expiresAt = block.timestamp.add(challengePeriod);
+ expiresAt = block.timestamp + challengePeriod;
emit ChallengeExit(msg.sender, nonce);
}
@@ -170,3 +167,7 @@ contract BiDirectionalPaymentChannel {
}
}
```
+
+## Teste no Remix
+
+-[BiDirectionalPaymentChannel.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8qCkFicmluZG8gdW0gY2FuYWwKMS4gQWxpY2UgZSBCb2IgZGVwb3NpdGFtIGVtIHVtYSBjYXJ0ZWlyYSBtdWx0aS1zaWcKMi4gRW5kZXJlY28gZGUgY2FuYWwgZGUgcGFnYW1lbnRvIGUgcHJlLWNvbXB1dGFkbwozLiBBbGljZSBlIEJvYiB0cm9jYW0gYXNzaW5hdHVyYXMgZG9zIGJhbGFuY29zIGluaWNpYWlzCjQuIEFsaWNlIGUgQm9iIGNyaWFtIHVtYSB0cmFuc2FjYW8gcXVlIHBvZGUgaW1wbGVtZW50YXIgdW0gY2FuYWwgZGUgcGFnYW1lbnRvIGRhCmNhcnRlaXJhIG11bHRpLXNpZwpBdHVhbGl6YXIgc2FsZG9zIGRvIGNhbmFsCjEuIFJlcGV0ZSBvcyBwYXNzb3MgMSAtIDMgZGEgYWJlcnR1cmEgZG8gY2FuYWwKMi4gRGEgY2FydGVpcmEgbXVsdGktc2lnIGNyaWEgdW1hIHRyYW5zYWNhbyBxdWUgdmFpCiAgIC0gYXBhZ2FyIGEgdHJhbnNhY2FvIHF1ZSB0ZXJpYSBpbXBsZW1lbnRhZG8gbyBjYW5hbCBkZSBwYWdhbWVudG8gYW50aWdvCiAgIC0gZSBkZXBvaXMgY3JpYSBhIHRyYW5zYWNhbyBxdWUgcG9kZSBpbXBsZW1lbnRhciB1bSBjYW5hbCBkZSBwYWdhbWVudG8gCiAgICAgY29tIG5vdm9zIGJhbGFuY29zCgpGZWNoYW5kbyB1bSBjYW5hbCBxdWFuZG8gQWxpY2UgZSBCb2IgY29uY29yZGFtIGNvbSBvIHNhbGRvIGZpbmFsCjEuIERhIGNhcnRlaXJhIG11bHRpLXNpZyBjcmlhIHVtYSB0cmFuc2FjYW8gcXVlIHZhaQogICAtIGVudmlhciBwYWdhbWVudG9zIHBhcmEgQWxpY2UgZSBCb2IKICAgLSBlIGRlcG9pcyBhcGFnYXIgYSB0cmFuc2FjYW8gcXVlIHRlcmlhIGNyaWFkbyBvIGNhbmFsIGRlIHBhZ2FtZW50bwoKRmVjaGFuZG8gdW0gY2FuYWwgcXVhbmRvIEFsaWNlIGUgQm9iIG5hbyBjb25jb3JkYW0gY29tIG9zIHNhbGRvcyBmaW5haXMKMS4gSW1wbGVtZW50YSBjYW5hbCBkZSBwYWdhbWVudG8gZGEgbXVsdGktc2lnCjIuIGNoYW1hIGNoYWxsZW5nZUV4aXQoKXBhcmEgaW5pY2lhciBvIHByb2Nlc3NvIGRlIGZlY2hhbWVudG8gZG8gY2FuYWwKMy4gQWxpY2UgZSBCb2IgcG9kZW0gcmV0aXJhciBmdW5kb3MgdW1hIHZleiBxdWUgbyBjYW5hbCBlIGV4dGludG8KKi8KCmltcG9ydCAiZ2l0aHViLmNvbS9PcGVuWmVwcGVsaW4vb3BlbnplcHBlbGluLWNvbnRyYWN0cy9ibG9iL3JlbGVhc2UtdjQuNS9jb250cmFjdHMvdXRpbHMvY3J5cHRvZ3JhcGh5L0VDRFNBLnNvbCI7Cgpjb250cmFjdCBCaURpcmVjdGlvbmFsUGF5bWVudENoYW5uZWwgewogICAgdXNpbmcgRUNEU0EgZm9yIGJ5dGVzMzI7CgogICAgZXZlbnQgQ2hhbGxlbmdlRXhpdChhZGRyZXNzIGluZGV4ZWQgc2VuZGVyLCB1aW50IG5vbmNlKTsKICAgIGV2ZW50IFdpdGhkcmF3KGFkZHJlc3MgaW5kZXhlZCB0bywgdWludCBhbW91bnQpOwoKICAgIGFkZHJlc3MgcGF5YWJsZVsyXSBwdWJsaWMgdXNlcnM7CiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gYm9vbCkgcHVibGljIGlzVXNlcjsKCiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gdWludCkgcHVibGljIGJhbGFuY2VzOwoKICAgIHVpbnQgcHVibGljIGNoYWxsZW5nZVBlcmlvZDsKICAgIHVpbnQgcHVibGljIGV4cGlyZXNBdDsKICAgIHVpbnQgcHVibGljIG5vbmNlOwoKICAgIG1vZGlmaWVyIGNoZWNrQmFsYW5jZXModWludFsyXSBtZW1vcnkgX2JhbGFuY2VzKSB7CiAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgYWRkcmVzcyh0aGlzKS5iYWxhbmNlID49IF9iYWxhbmNlc1swXSArIF9iYWxhbmNlc1sxXSwKICAgICAgICAgICAgImJhbGFuY2Ugb2YgY29udHJhY3QgbXVzdCBiZSA+PSB0byB0aGUgdG90YWwgYmFsYW5jZSBvZiB1c2VycyIKICAgICAgICApOwogICAgICAgIF87CiAgICB9CgogICAgLy8gTk9UQTogZGVwb3NpdGFyIGRlIHVtYSBjYXJ0ZWlyYSBtdWx0aS1zaWcKICAgIGNvbnN0cnVjdG9yKAogICAgICAgIGFkZHJlc3MgcGF5YWJsZVsyXSBtZW1vcnkgX3VzZXJzLAogICAgICAgIHVpbnRbMl0gbWVtb3J5IF9iYWxhbmNlcywKICAgICAgICB1aW50IF9leHBpcmVzQXQsCiAgICAgICAgdWludCBfY2hhbGxlbmdlUGVyaW9kCiAgICApIHBheWFibGUgY2hlY2tCYWxhbmNlcyhfYmFsYW5jZXMpIHsKICAgICAgICByZXF1aXJlKF9leHBpcmVzQXQgPiBibG9jay50aW1lc3RhbXAsICJFeHBpcmF0aW9uIG11c3QgYmUgPiBub3ciKTsKICAgICAgICByZXF1aXJlKF9jaGFsbGVuZ2VQZXJpb2QgPiAwLCAiQ2hhbGxlbmdlIHBlcmlvZCBtdXN0IGJlID4gMCIpOwoKICAgICAgICBmb3IgKHVpbnQgaSA9IDA7IGkgPCBfdXNlcnMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgYWRkcmVzcyBwYXlhYmxlIHVzZXIgPSBfdXNlcnNbaV07CgogICAgICAgICAgICByZXF1aXJlKCFpc1VzZXJbdXNlcl0sICJ1c2VyIG11c3QgYmUgdW5pcXVlIik7CiAgICAgICAgICAgIHVzZXJzW2ldID0gdXNlcjsKICAgICAgICAgICAgaXNVc2VyW3VzZXJdID0gdHJ1ZTsKCiAgICAgICAgICAgIGJhbGFuY2VzW3VzZXJdID0gX2JhbGFuY2VzW2ldOwogICAgICAgIH0KCiAgICAgICAgZXhwaXJlc0F0ID0gX2V4cGlyZXNBdDsKICAgICAgICBjaGFsbGVuZ2VQZXJpb2QgPSBfY2hhbGxlbmdlUGVyaW9kOwogICAgfQoKICAgIGZ1bmN0aW9uIHZlcmlmeSgKICAgICAgICBieXRlc1syXSBtZW1vcnkgX3NpZ25hdHVyZXMsCiAgICAgICAgYWRkcmVzcyBfY29udHJhY3QsCiAgICAgICAgYWRkcmVzc1syXSBtZW1vcnkgX3NpZ25lcnMsCiAgICAgICAgdWludFsyXSBtZW1vcnkgX2JhbGFuY2VzLAogICAgICAgIHVpbnQgX25vbmNlCiAgICApIHB1YmxpYyBwdXJlIHJldHVybnMgKGJvb2wpIHsKICAgICAgICBmb3IgKHVpbnQgaSA9IDA7IGkgPCBfc2lnbmF0dXJlcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICAvKgogICAgICAgICAgICBOT1RBOiBhc3NpbmEgY29tIGVuZGVyZWNvIGRlc3NlIGNvbnRyYXRvIHBhcmEgcHJvdGVnZXIKICAgICAgICAgICAgICAgICAgY29udHJhIGF0YXF1ZSBkZSByZXBldGljYW8gZW0gb3V0cm9zIGNvbnRyYXRvcwogICAgICAgICAgICAqLwogICAgICAgICAgICBib29sIHZhbGlkID0gX3NpZ25lcnNbaV0gPT0KICAgICAgICAgICAgICAgIGtlY2NhazI1NihhYmkuZW5jb2RlUGFja2VkKF9jb250cmFjdCwgX2JhbGFuY2VzLCBfbm9uY2UpKQogICAgICAgICAgICAgICAgLnRvRXRoU2lnbmVkTWVzc2FnZUhhc2goKQogICAgICAgICAgICAgICAgLnJlY292ZXIoX3NpZ25hdHVyZXNbaV0pOwoKICAgICAgICAgICAgaWYgKCF2YWxpZCkgewogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBtb2RpZmllciBjaGVja1NpZ25hdHVyZXMoCiAgICAgICAgYnl0ZXNbMl0gbWVtb3J5IF9zaWduYXR1cmVzLAogICAgICAgIHVpbnRbMl0gbWVtb3J5IF9iYWxhbmNlcywKICAgICAgICB1aW50IF9ub25jZQogICAgKSB7CiAgICAgICAgLy8gTm90ZTogY29weSBzdG9yYWdlIGFycmF5IHRvIG1lbW9yeQogICAgICAgIGFkZHJlc3NbMl0gbWVtb3J5IHNpZ25lcnM7CiAgICAgICAgZm9yICh1aW50IGkgPSAwOyBpIDwgdXNlcnMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgc2lnbmVyc1tpXSA9IHVzZXJzW2ldOwogICAgICAgIH0KCiAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgdmVyaWZ5KF9zaWduYXR1cmVzLCBhZGRyZXNzKHRoaXMpLCBzaWduZXJzLCBfYmFsYW5jZXMsIF9ub25jZSksCiAgICAgICAgICAgICJJbnZhbGlkIHNpZ25hdHVyZSIKICAgICAgICApOwoKICAgICAgICBfOwogICAgfQoKICAgIG1vZGlmaWVyIG9ubHlVc2VyKCkgewogICAgICAgIHJlcXVpcmUoaXNVc2VyW21zZy5zZW5kZXJdLCAiTm90IHVzZXIiKTsKICAgICAgICBfOwogICAgfQoKICAgIGZ1bmN0aW9uIGNoYWxsZW5nZUV4aXQoCiAgICAgICAgdWludFsyXSBtZW1vcnkgX2JhbGFuY2VzLAogICAgICAgIHVpbnQgX25vbmNlLAogICAgICAgIGJ5dGVzWzJdIG1lbW9yeSBfc2lnbmF0dXJlcwogICAgKQogICAgICAgIHB1YmxpYwogICAgICAgIG9ubHlVc2VyCiAgICAgICAgY2hlY2tTaWduYXR1cmVzKF9zaWduYXR1cmVzLCBfYmFsYW5jZXMsIF9ub25jZSkKICAgICAgICBjaGVja0JhbGFuY2VzKF9iYWxhbmNlcykKICAgIHsKICAgICAgICByZXF1aXJlKGJsb2NrLnRpbWVzdGFtcCA8IGV4cGlyZXNBdCwgIkV4cGlyZWQgY2hhbGxlbmdlIHBlcmlvZCIpOwogICAgICAgIHJlcXVpcmUoX25vbmNlID4gbm9uY2UsICJOb25jZSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB0aGUgY3VycmVudCBub25jZSIpOwoKICAgICAgICBmb3IgKHVpbnQgaSA9IDA7IGkgPCBfYmFsYW5jZXMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgYmFsYW5jZXNbdXNlcnNbaV1dID0gX2JhbGFuY2VzW2ldOwogICAgICAgIH0KCiAgICAgICAgbm9uY2UgPSBfbm9uY2U7CiAgICAgICAgZXhwaXJlc0F0ID0gYmxvY2sudGltZXN0YW1wICsgY2hhbGxlbmdlUGVyaW9kOwoKICAgICAgICBlbWl0IENoYWxsZW5nZUV4aXQobXNnLnNlbmRlciwgbm9uY2UpOwogICAgfQoKICAgIGZ1bmN0aW9uIHdpdGhkcmF3KCkgcHVibGljIG9ubHlVc2VyIHsKICAgICAgICByZXF1aXJlKGJsb2NrLnRpbWVzdGFtcCA+PSBleHBpcmVzQXQsICJDaGFsbGVuZ2UgcGVyaW9kIGhhcyBub3QgZXhwaXJlZCB5ZXQiKTsKCiAgICAgICAgdWludCBhbW91bnQgPSBiYWxhbmNlc1ttc2cuc2VuZGVyXTsKICAgICAgICBiYWxhbmNlc1ttc2cuc2VuZGVyXSA9IDA7CgogICAgICAgIChib29sIHNlbnQsICkgPSBtc2cuc2VuZGVyLmNhbGx7dmFsdWU6IGFtb3VudH0oIiIpOwogICAgICAgIHJlcXVpcmUoc2VudCwgIkZhaWxlZCB0byBzZW5kIEV0aGVyIik7CgogICAgICAgIGVtaXQgV2l0aGRyYXcobXNnLnNlbmRlciwgYW1vdW50KTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/canal-de-pagamento-unidirecional.md b/src/exemplos/aplicacoes/canal-de-pagamento-unidirecional.md
index 189e3a8..d9202aa 100644
--- a/src/exemplos/aplicacoes/canal-de-pagamento-unidirecional.md
+++ b/src/exemplos/aplicacoes/canal-de-pagamento-unidirecional.md
@@ -1,6 +1,6 @@
# Canal de Pagamento Unidirecional
-Canais de pagamento permitem que participantes transfiram Ether off chain repetidamente
+Os canais de pagamento permitem que os participantes transfiram repetidamente o Ether para fora da cadeia.
Aqui está como esse contrato é usado:
@@ -13,10 +13,10 @@ Esse é chamado um canal de pagamento unidirecional já que o pagamento só pode
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
-import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol";
-import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/utils/ReentrancyGuard.sol";
+import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/utils/cryptography/ECDSA.sol";
+import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.5/contracts/security/ReentrancyGuard.sol";
contract UniDirectionalPaymentChannel is ReentrancyGuard {
using ECDSA for bytes32;
@@ -29,34 +29,34 @@ contract UniDirectionalPaymentChannel is ReentrancyGuard {
constructor(address payable _receiver) payable {
require(_receiver != address(0), "receiver = zero address");
- sender = msg.sender;
+ sender = payable(msg.sender);
receiver = _receiver;
expiresAt = block.timestamp + DURATION;
}
- function _getHash(uint _amount) private pure returns (bytes32) {
- // NOTA: assine com endereço desse contrato para proteção contra
+ function _getHash(uint _amount) private view returns (bytes32) {
+ // NOTA: assine com endereço desse contrato para proteção contra
// ataque de repetição em outros contratos
return keccak256(abi.encodePacked(address(this), _amount));
}
- function getHash(uint _amount) external pure returns (bytes32) {
+ function getHash(uint _amount) external view returns (bytes32) {
return _getHash(_amount);
}
- function _getEthSignedHash(uint _amount) private pure returns (bytes32) {
+ function _getEthSignedHash(uint _amount) private view returns (bytes32) {
return _getHash(_amount).toEthSignedMessageHash();
}
- function getEthSignedHash(uint _amount) external pure returns (bytes32) {
+ function getEthSignedHash(uint _amount) external view returns (bytes32) {
return _getEthSignedHash(_amount);
}
- function _verify(uint _amount bytes memory _sig) private view returns (bool) {
+ function _verify(uint _amount, bytes memory _sig) private view returns (bool) {
return _getEthSignedHash(_amount).recover(_sig) == sender;
}
- function verify(uint _amount bytes memory _sig) external view returns (bool) {
+ function verify(uint _amount, bytes memory _sig) external view returns (bool) {
return _verify(_amount, _sig);
}
@@ -76,3 +76,7 @@ contract UniDirectionalPaymentChannel is ReentrancyGuard {
}
}
```
+
+## Teste no Remix
+
+- [UniDirectionalPaymentChannel.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCAiZ2l0aHViLmNvbS9PcGVuWmVwcGVsaW4vb3BlbnplcHBlbGluLWNvbnRyYWN0cy9ibG9iL3JlbGVhc2UtdjQuNS9jb250cmFjdHMvdXRpbHMvY3J5cHRvZ3JhcGh5L0VDRFNBLnNvbCI7CmltcG9ydCAiZ2l0aHViLmNvbS9PcGVuWmVwcGVsaW4vb3BlbnplcHBlbGluLWNvbnRyYWN0cy9ibG9iL3JlbGVhc2UtdjQuNS9jb250cmFjdHMvc2VjdXJpdHkvUmVlbnRyYW5jeUd1YXJkLnNvbCI7Cgpjb250cmFjdCBVbmlEaXJlY3Rpb25hbFBheW1lbnRDaGFubmVsIGlzIFJlZW50cmFuY3lHdWFyZCB7CiAgICB1c2luZyBFQ0RTQSBmb3IgYnl0ZXMzMjsKCiAgICBhZGRyZXNzIHBheWFibGUgcHVibGljIHNlbmRlcjsKICAgIGFkZHJlc3MgcGF5YWJsZSBwdWJsaWMgcmVjZWl2ZXI7CgogICAgdWludCBwcml2YXRlIGNvbnN0YW50IERVUkFUSU9OID0gNyAqIDI0ICogNjAgKiA2MDsKICAgIHVpbnQgcHVibGljIGV4cGlyZXNBdDsKCiAgICBjb25zdHJ1Y3RvcihhZGRyZXNzIHBheWFibGUgX3JlY2VpdmVyKSBwYXlhYmxlIHsKICAgICAgICByZXF1aXJlKF9yZWNlaXZlciAhPSBhZGRyZXNzKDApLCAicmVjZWl2ZXIgPSB6ZXJvIGFkZHJlc3MiKTsKICAgICAgICBzZW5kZXIgPSBwYXlhYmxlKG1zZy5zZW5kZXIpOwogICAgICAgIHJlY2VpdmVyID0gX3JlY2VpdmVyOwogICAgICAgIGV4cGlyZXNBdCA9IGJsb2NrLnRpbWVzdGFtcCArIERVUkFUSU9OOwogICAgfQoKICAgIGZ1bmN0aW9uIF9nZXRIYXNoKHVpbnQgX2Ftb3VudCkgcHJpdmF0ZSB2aWV3IHJldHVybnMgKGJ5dGVzMzIpIHsKICAgICAgICAgLy8gTk9UQTogYXNzaW5lIGNvbSBlbmRlcmVjbyBkZXNzZSBjb250cmF0byBwYXJhIHByb3RlY2FvIGNvbnRyYQogICAgICAgIC8vIGF0YXF1ZSBkZSByZXBldGljYW8gZW0gb3V0cm9zIGNvbnRyYXRvcwogICAgICAgIHJldHVybiBrZWNjYWsyNTYoYWJpLmVuY29kZVBhY2tlZChhZGRyZXNzKHRoaXMpLCBfYW1vdW50KSk7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0SGFzaCh1aW50IF9hbW91bnQpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoYnl0ZXMzMikgewogICAgICAgIHJldHVybiBfZ2V0SGFzaChfYW1vdW50KTsKICAgIH0KCiAgICBmdW5jdGlvbiBfZ2V0RXRoU2lnbmVkSGFzaCh1aW50IF9hbW91bnQpIHByaXZhdGUgdmlldyByZXR1cm5zIChieXRlczMyKSB7CiAgICAgICAgcmV0dXJuIF9nZXRIYXNoKF9hbW91bnQpLnRvRXRoU2lnbmVkTWVzc2FnZUhhc2goKTsKICAgIH0KCiAgICBmdW5jdGlvbiBnZXRFdGhTaWduZWRIYXNoKHVpbnQgX2Ftb3VudCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChieXRlczMyKSB7CiAgICAgICAgcmV0dXJuIF9nZXRFdGhTaWduZWRIYXNoKF9hbW91bnQpOwogICAgfQoKICAgIGZ1bmN0aW9uIF92ZXJpZnkodWludCBfYW1vdW50LCBieXRlcyBtZW1vcnkgX3NpZykgcHJpdmF0ZSB2aWV3IHJldHVybnMgKGJvb2wpIHsKICAgICAgICByZXR1cm4gX2dldEV0aFNpZ25lZEhhc2goX2Ftb3VudCkucmVjb3Zlcihfc2lnKSA9PSBzZW5kZXI7CiAgICB9CgogICAgZnVuY3Rpb24gdmVyaWZ5KHVpbnQgX2Ftb3VudCwgYnl0ZXMgbWVtb3J5IF9zaWcpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybiBfdmVyaWZ5KF9hbW91bnQsIF9zaWcpOwogICAgfQoKICAgIGZ1bmN0aW9uIGNsb3NlKHVpbnQgX2Ftb3VudCwgYnl0ZXMgbWVtb3J5IF9zaWcpIGV4dGVybmFsIG5vblJlZW50cmFudCB7CiAgICAgICAgcmVxdWlyZShtc2cuc2VuZGVyID09IHJlY2VpdmVyLCAiIXJlY2VpdmVyIik7CiAgICAgICAgcmVxdWlyZShfdmVyaWZ5KF9hbW91bnQsIF9zaWcpLCAiaW52YWxpZCBzaWciKTsKCiAgICAgICAgKGJvb2wgc2VudCwgKSA9IHJlY2VpdmVyLmNhbGx7dmFsdWU6IF9hbW91bnR9KCIiKTsKICAgICAgICByZXF1aXJlKHNlbnQsICJGYWlsZWQgdG8gc2VuZCBFdGhlciIpOwogICAgICAgIHNlbGZkZXN0cnVjdChzZW5kZXIpOwogICAgfQoKICAgIGZ1bmN0aW9uIGNhbmNlbCgpIGV4dGVybmFsIHsKICAgICAgICByZXF1aXJlKG1zZy5zZW5kZXIgPT0gc2VuZGVyLCAiIXNlbmRlciIpOwogICAgICAgIHJlcXVpcmUoYmxvY2sudGltZXN0YW1wID49IGV4cGlyZXNBdCwgIiFleHBpcmVkIik7CiAgICAgICAgc2VsZmRlc3RydWN0KHNlbmRlcik7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
\ No newline at end of file
diff --git a/src/exemplos/aplicacoes/carteira-ether.md b/src/exemplos/aplicacoes/carteira-ether.md
new file mode 100644
index 0000000..6561ddb
--- /dev/null
+++ b/src/exemplos/aplicacoes/carteira-ether.md
@@ -0,0 +1,34 @@
+# Carteira Ether
+
+Um exemplo de uma carteira básica.
+
+- Qualquer pessoa pode enviar ETH.
+- Somente o proprietário pode retirar.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+contract EtherWallet {
+ address payable public owner;
+
+ constructor() {
+ owner = payable(msg.sender);
+ }
+
+ receive() external payable {}
+
+ function withdraw(uint _amount) external {
+ require(msg.sender == owner, "Quem está chamando não é o dono");
+ payable(msg.sender).transfer(_amount);
+ }
+
+ function getBalance() external view returns (uint) {
+ return address(this).balance;
+ }
+}
+```
+
+## Teste no Remix
+
+- [EtherWallet.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IEV0aGVyV2FsbGV0IHsKICAgIGFkZHJlc3MgcGF5YWJsZSBwdWJsaWMgb3duZXI7CgogICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgb3duZXIgPSBwYXlhYmxlKG1zZy5zZW5kZXIpOwogICAgfQoKICAgIHJlY2VpdmUoKSBleHRlcm5hbCBwYXlhYmxlIHt9CgogICAgZnVuY3Rpb24gd2l0aGRyYXcodWludCBfYW1vdW50KSBleHRlcm5hbCB7CiAgICAgICAgcmVxdWlyZShtc2cuc2VuZGVyID09IG93bmVyLCAiUXVlbSBlc3RhIGNoYW1hbmRvIG5hbyBlIG8gZG9ubyIpOwogICAgICAgIHBheWFibGUobXNnLnNlbmRlcikudHJhbnNmZXIoX2Ftb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0QmFsYW5jZSgpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAodWludCkgewogICAgICAgIHJldHVybiBhZGRyZXNzKHRoaXMpLmJhbGFuY2U7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
\ No newline at end of file
diff --git a/src/exemplos/aplicacoes/carteira-multi-assinaturas.md b/src/exemplos/aplicacoes/carteira-multi-assinaturas.md
index 6e51d76..c9a52fa 100644
--- a/src/exemplos/aplicacoes/carteira-multi-assinaturas.md
+++ b/src/exemplos/aplicacoes/carteira-multi-assinaturas.md
@@ -4,13 +4,13 @@ Vamos criar uma carteira multi-sig. Aqui estão as especificações.
Os proprietários da carteira podem
-* submeter uma transação
-* aprovar e revogar aprovação de transações pendentes
-* qualquer um pode executar uma transação depois que os proprietários tenham aprovado.
+- submeter uma transação
+- aprovar e revogar aprovação de transações pendentes
+- qualquer um pode executar uma transação depois que os proprietários tenham aprovado.
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
contract MultiSigWallet {
event Deposit(address indexed sender, uint amount, uint balance);
@@ -43,38 +43,38 @@ contract MultiSigWallet {
Transaction[] public transactions;
modifier onlyOwner() {
- require(isOwner[msg.sender], "not owner");
+ require(isOwner[msg.sender], "Não é o dono");
_;
}
modifier txExists(uint _txIndex) {
- require(_txIndex < transactions.length, "tx does not exist");
+ require(_txIndex < transactions.length, "tx não existe");
_;
}
modifier notExecuted(uint _txIndex) {
- require(!transactions[_txIndex].executed, "tx already executed");
+ require(!transactions[_txIndex].executed, "tx já executado");
_;
}
modifier notConfirmed(uint _txIndex) {
- require(!isConfirmed[_txIndex][msg.sender], "tx already confirmed");
+ require(!isConfirmed[_txIndex][msg.sender], "tx já confirmado");
_;
}
constructor(address[] memory _owners, uint _numConfirmationsRequired) {
- require(_owners.length > 0, "owners required");
+ require(_owners.length > 0, "precisa do dono");
require(
_numConfirmationsRequired > 0 &&
_numConfirmationsRequired <= _owners.length,
- "invalid number of required confirmations"
+ "número inválido de confirmações necessárias"
);
for (uint i = 0; i < _owners.length; i++) {
address owner = _owners[i];
- require(owner != address(0), "invalid owner");
- require(!isOwner[owner], "owner not unique");
+ require(owner != address(0), "dono inválido");
+ require(!isOwner[owner], "dono n]ap é único");
isOwner[owner] = true;
owners.push(owner);
@@ -131,7 +131,7 @@ contract MultiSigWallet {
require(
transaction.numConfirmations >= numConfirmationsRequired,
- "cannot execute tx"
+ "não pode executar tx"
);
transaction.executed = true;
@@ -139,7 +139,7 @@ contract MultiSigWallet {
(bool success, ) = transaction.to.call{value: transaction.value}(
transaction.data
);
- require(success, "tx failed");
+ require(success, "tx falhou");
emit ExecuteTransaction(msg.sender, _txIndex);
}
@@ -152,7 +152,7 @@ contract MultiSigWallet {
{
Transaction storage transaction = transactions[_txIndex];
- require(isConfirmed[_txIndex][msg.sender], "tx not confirmed");
+ require(isConfirmed[_txIndex][msg.sender], "tx não confirmado");
transaction.numConfirmations -= 1;
isConfirmed[_txIndex][msg.sender] = false;
@@ -192,11 +192,11 @@ contract MultiSigWallet {
}
```
-Eis aqui um contrato para testar envio de transações de uma carteira multi-sig
+Aqui está um contrato para testar o envio de transações da carteira multi-sig
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
contract TestContract {
uint public i;
@@ -210,3 +210,8 @@ contract TestContract {
}
}
```
+
+## Teste no Remix
+
+- [MultiSigWallet.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IE11bHRpU2lnV2FsbGV0IHsKICAgIGV2ZW50IERlcG9zaXQoYWRkcmVzcyBpbmRleGVkIHNlbmRlciwgdWludCBhbW91bnQsIHVpbnQgYmFsYW5jZSk7CiAgICBldmVudCBTdWJtaXRUcmFuc2FjdGlvbigKICAgICAgICBhZGRyZXNzIGluZGV4ZWQgb3duZXIsCiAgICAgICAgdWludCBpbmRleGVkIHR4SW5kZXgsCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIHRvLAogICAgICAgIHVpbnQgdmFsdWUsCiAgICAgICAgYnl0ZXMgZGF0YQogICAgKTsKICAgIGV2ZW50IENvbmZpcm1UcmFuc2FjdGlvbihhZGRyZXNzIGluZGV4ZWQgb3duZXIsIHVpbnQgaW5kZXhlZCB0eEluZGV4KTsKICAgIGV2ZW50IFJldm9rZUNvbmZpcm1hdGlvbihhZGRyZXNzIGluZGV4ZWQgb3duZXIsIHVpbnQgaW5kZXhlZCB0eEluZGV4KTsKICAgIGV2ZW50IEV4ZWN1dGVUcmFuc2FjdGlvbihhZGRyZXNzIGluZGV4ZWQgb3duZXIsIHVpbnQgaW5kZXhlZCB0eEluZGV4KTsKCiAgICBhZGRyZXNzW10gcHVibGljIG93bmVyczsKICAgIG1hcHBpbmcoYWRkcmVzcyA9PiBib29sKSBwdWJsaWMgaXNPd25lcjsKICAgIHVpbnQgcHVibGljIG51bUNvbmZpcm1hdGlvbnNSZXF1aXJlZDsKCiAgICBzdHJ1Y3QgVHJhbnNhY3Rpb24gewogICAgICAgIGFkZHJlc3MgdG87CiAgICAgICAgdWludCB2YWx1ZTsKICAgICAgICBieXRlcyBkYXRhOwogICAgICAgIGJvb2wgZXhlY3V0ZWQ7CiAgICAgICAgdWludCBudW1Db25maXJtYXRpb25zOwogICAgfQoKICAgIC8vIG1hcHBpbmcgZGUgdHggaW5kZXggPT4gb3duZXIgPT4gYm9vbAogICAgbWFwcGluZyh1aW50ID0+IG1hcHBpbmcoYWRkcmVzcyA9PiBib29sKSkgcHVibGljIGlzQ29uZmlybWVkOwoKICAgIFRyYW5zYWN0aW9uW10gcHVibGljIHRyYW5zYWN0aW9uczsKCiAgICBtb2RpZmllciBvbmx5T3duZXIoKSB7CiAgICAgICAgcmVxdWlyZShpc093bmVyW21zZy5zZW5kZXJdLCAiTmFvIGUgIG8gZG9ubyIpOwogICAgICAgIF87CiAgICB9CgogICAgbW9kaWZpZXIgdHhFeGlzdHModWludCBfdHhJbmRleCkgewogICAgICAgIHJlcXVpcmUoX3R4SW5kZXggPCB0cmFuc2FjdGlvbnMubGVuZ3RoLCAidHggbmFvIGV4aXN0ZSIpOwogICAgICAgIF87CiAgICB9CgogICAgbW9kaWZpZXIgbm90RXhlY3V0ZWQodWludCBfdHhJbmRleCkgewogICAgICAgIHJlcXVpcmUoIXRyYW5zYWN0aW9uc1tfdHhJbmRleF0uZXhlY3V0ZWQsICJ0eCBqYSBleGVjdXRhZG8iKTsKICAgICAgICBfOwogICAgfQoKICAgIG1vZGlmaWVyIG5vdENvbmZpcm1lZCh1aW50IF90eEluZGV4KSB7CiAgICAgICAgcmVxdWlyZSghaXNDb25maXJtZWRbX3R4SW5kZXhdW21zZy5zZW5kZXJdLCAidHggamEgY29uZmlybWFkbyIpOwogICAgICAgIF87CiAgICB9CgogICAgY29uc3RydWN0b3IoYWRkcmVzc1tdIG1lbW9yeSBfb3duZXJzLCB1aW50IF9udW1Db25maXJtYXRpb25zUmVxdWlyZWQpIHsKICAgICAgICByZXF1aXJlKF9vd25lcnMubGVuZ3RoID4gMCwgInByZWNpc2EgZG8gZG9ubyIpOwogICAgICAgIHJlcXVpcmUoCiAgICAgICAgICAgIF9udW1Db25maXJtYXRpb25zUmVxdWlyZWQgPiAwICYmCiAgICAgICAgICAgICAgICBfbnVtQ29uZmlybWF0aW9uc1JlcXVpcmVkIDw9IF9vd25lcnMubGVuZ3RoLAogICAgICAgICAgICAibnVtZXJvIGludmFsaWRvIGRlIGNvbmZpcm1hY29lcyBuZWNlc3NhcmlhcyIKICAgICAgICApOwoKICAgICAgICBmb3IgKHVpbnQgaSA9IDA7IGkgPCBfb3duZXJzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgICAgIGFkZHJlc3Mgb3duZXIgPSBfb3duZXJzW2ldOwoKICAgICAgICAgICAgcmVxdWlyZShvd25lciAhPSBhZGRyZXNzKDApLCAiZG9ubyBpbnZhbGlkbyIpOwogICAgICAgICAgICByZXF1aXJlKCFpc093bmVyW293bmVyXSwgImRvbm8gbl1hcCBlIHVuaWNvIik7CgogICAgICAgICAgICBpc093bmVyW293bmVyXSA9IHRydWU7CiAgICAgICAgICAgIG93bmVycy5wdXNoKG93bmVyKTsKICAgICAgICB9CgogICAgICAgIG51bUNvbmZpcm1hdGlvbnNSZXF1aXJlZCA9IF9udW1Db25maXJtYXRpb25zUmVxdWlyZWQ7CiAgICB9CgogICAgcmVjZWl2ZSgpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIGVtaXQgRGVwb3NpdChtc2cuc2VuZGVyLCBtc2cudmFsdWUsIGFkZHJlc3ModGhpcykuYmFsYW5jZSk7CiAgICB9CgogICAgZnVuY3Rpb24gc3VibWl0VHJhbnNhY3Rpb24oCiAgICAgICAgYWRkcmVzcyBfdG8sCiAgICAgICAgdWludCBfdmFsdWUsCiAgICAgICAgYnl0ZXMgbWVtb3J5IF9kYXRhCiAgICApIHB1YmxpYyBvbmx5T3duZXIgewogICAgICAgIHVpbnQgdHhJbmRleCA9IHRyYW5zYWN0aW9ucy5sZW5ndGg7CgogICAgICAgIHRyYW5zYWN0aW9ucy5wdXNoKAogICAgICAgICAgICBUcmFuc2FjdGlvbih7CiAgICAgICAgICAgICAgICB0bzogX3RvLAogICAgICAgICAgICAgICAgdmFsdWU6IF92YWx1ZSwKICAgICAgICAgICAgICAgIGRhdGE6IF9kYXRhLAogICAgICAgICAgICAgICAgZXhlY3V0ZWQ6IGZhbHNlLAogICAgICAgICAgICAgICAgbnVtQ29uZmlybWF0aW9uczogMAogICAgICAgICAgICB9KQogICAgICAgICk7CgogICAgICAgIGVtaXQgU3VibWl0VHJhbnNhY3Rpb24obXNnLnNlbmRlciwgdHhJbmRleCwgX3RvLCBfdmFsdWUsIF9kYXRhKTsKICAgIH0KCiAgICBmdW5jdGlvbiBjb25maXJtVHJhbnNhY3Rpb24odWludCBfdHhJbmRleCkKICAgICAgICBwdWJsaWMKICAgICAgICBvbmx5T3duZXIKICAgICAgICB0eEV4aXN0cyhfdHhJbmRleCkKICAgICAgICBub3RFeGVjdXRlZChfdHhJbmRleCkKICAgICAgICBub3RDb25maXJtZWQoX3R4SW5kZXgpCiAgICB7CiAgICAgICAgVHJhbnNhY3Rpb24gc3RvcmFnZSB0cmFuc2FjdGlvbiA9IHRyYW5zYWN0aW9uc1tfdHhJbmRleF07CiAgICAgICAgdHJhbnNhY3Rpb24ubnVtQ29uZmlybWF0aW9ucyArPSAxOwogICAgICAgIGlzQ29uZmlybWVkW190eEluZGV4XVttc2cuc2VuZGVyXSA9IHRydWU7CgogICAgICAgIGVtaXQgQ29uZmlybVRyYW5zYWN0aW9uKG1zZy5zZW5kZXIsIF90eEluZGV4KTsKICAgIH0KCiAgICBmdW5jdGlvbiBleGVjdXRlVHJhbnNhY3Rpb24odWludCBfdHhJbmRleCkKICAgICAgICBwdWJsaWMKICAgICAgICBvbmx5T3duZXIKICAgICAgICB0eEV4aXN0cyhfdHhJbmRleCkKICAgICAgICBub3RFeGVjdXRlZChfdHhJbmRleCkKICAgIHsKICAgICAgICBUcmFuc2FjdGlvbiBzdG9yYWdlIHRyYW5zYWN0aW9uID0gdHJhbnNhY3Rpb25zW190eEluZGV4XTsKCiAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgdHJhbnNhY3Rpb24ubnVtQ29uZmlybWF0aW9ucyA+PSBudW1Db25maXJtYXRpb25zUmVxdWlyZWQsCiAgICAgICAgICAgICJuYW8gcG9kZSBleGVjdXRhciB0eCIKICAgICAgICApOwoKICAgICAgICB0cmFuc2FjdGlvbi5leGVjdXRlZCA9IHRydWU7CgogICAgICAgIChib29sIHN1Y2Nlc3MsICkgPSB0cmFuc2FjdGlvbi50by5jYWxse3ZhbHVlOiB0cmFuc2FjdGlvbi52YWx1ZX0oCiAgICAgICAgICAgIHRyYW5zYWN0aW9uLmRhdGEKICAgICAgICApOwogICAgICAgIHJlcXVpcmUoc3VjY2VzcywgInR4IGZhbGhvdSIpOwoKICAgICAgICBlbWl0IEV4ZWN1dGVUcmFuc2FjdGlvbihtc2cuc2VuZGVyLCBfdHhJbmRleCk7CiAgICB9CgogICAgZnVuY3Rpb24gcmV2b2tlQ29uZmlybWF0aW9uKHVpbnQgX3R4SW5kZXgpCiAgICAgICAgcHVibGljCiAgICAgICAgb25seU93bmVyCiAgICAgICAgdHhFeGlzdHMoX3R4SW5kZXgpCiAgICAgICAgbm90RXhlY3V0ZWQoX3R4SW5kZXgpCiAgICB7CiAgICAgICAgVHJhbnNhY3Rpb24gc3RvcmFnZSB0cmFuc2FjdGlvbiA9IHRyYW5zYWN0aW9uc1tfdHhJbmRleF07CgogICAgICAgIHJlcXVpcmUoaXNDb25maXJtZWRbX3R4SW5kZXhdW21zZy5zZW5kZXJdLCAidHggbmFvIGNvbmZpcm1hZG8iKTsKCiAgICAgICAgdHJhbnNhY3Rpb24ubnVtQ29uZmlybWF0aW9ucyAtPSAxOwogICAgICAgIGlzQ29uZmlybWVkW190eEluZGV4XVttc2cuc2VuZGVyXSA9IGZhbHNlOwoKICAgICAgICBlbWl0IFJldm9rZUNvbmZpcm1hdGlvbihtc2cuc2VuZGVyLCBfdHhJbmRleCk7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0T3duZXJzKCkgcHVibGljIHZpZXcgcmV0dXJucyAoYWRkcmVzc1tdIG1lbW9yeSkgewogICAgICAgIHJldHVybiBvd25lcnM7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25Db3VudCgpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQpIHsKICAgICAgICByZXR1cm4gdHJhbnNhY3Rpb25zLmxlbmd0aDsKICAgIH0KCiAgICBmdW5jdGlvbiBnZXRUcmFuc2FjdGlvbih1aW50IF90eEluZGV4KQogICAgICAgIHB1YmxpYwogICAgICAgIHZpZXcKICAgICAgICByZXR1cm5zICgKICAgICAgICAgICAgYWRkcmVzcyB0bywKICAgICAgICAgICAgdWludCB2YWx1ZSwKICAgICAgICAgICAgYnl0ZXMgbWVtb3J5IGRhdGEsCiAgICAgICAgICAgIGJvb2wgZXhlY3V0ZWQsCiAgICAgICAgICAgIHVpbnQgbnVtQ29uZmlybWF0aW9ucwogICAgICAgICkKICAgIHsKICAgICAgICBUcmFuc2FjdGlvbiBzdG9yYWdlIHRyYW5zYWN0aW9uID0gdHJhbnNhY3Rpb25zW190eEluZGV4XTsKCiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgdHJhbnNhY3Rpb24udG8sCiAgICAgICAgICAgIHRyYW5zYWN0aW9uLnZhbHVlLAogICAgICAgICAgICB0cmFuc2FjdGlvbi5kYXRhLAogICAgICAgICAgICB0cmFuc2FjdGlvbi5leGVjdXRlZCwKICAgICAgICAgICAgdHJhbnNhY3Rpb24ubnVtQ29uZmlybWF0aW9ucwogICAgICAgICk7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
+- [TestContract.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IFRlc3RDb250cmFjdCB7CiAgICB1aW50IHB1YmxpYyBpOwoKICAgIGZ1bmN0aW9uIGNhbGxNZSh1aW50IGopIHB1YmxpYyB7CiAgICAgICAgaSArPSBqOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldERhdGEoKSBwdWJsaWMgcHVyZSByZXR1cm5zIChieXRlcyBtZW1vcnkpIHsKICAgICAgICByZXR1cm4gYWJpLmVuY29kZVdpdGhTaWduYXR1cmUoImNhbGxNZSh1aW50MjU2KSIsIDEyMyk7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/contrato-de-bytecode-simples.md b/src/exemplos/aplicacoes/contrato-de-bytecode-simples.md
new file mode 100644
index 0000000..b0a7db5
--- /dev/null
+++ b/src/exemplos/aplicacoes/contrato-de-bytecode-simples.md
@@ -0,0 +1,66 @@
+# Contrato de Bytecode simples
+
+Exemplo simples de contrato escrito em bytecode
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+contract Factory {
+ event Log(address addr);
+
+ // Deploys a contract that always returns 42
+ function deploy() external {
+ bytes memory bytecode = hex"69602a60005260206000f3600052600a6016f3";
+ address addr;
+ assembly {
+ // create(value, offset, size)
+ addr := create(0, add(bytecode, 0x20), 0x13)
+ }
+ require(addr != address(0));
+
+ emit Log(addr);
+ }
+}
+
+interface IContract {
+ function getMeaningOfLife() external view returns (uint);
+}
+
+// https://www.evm.codes/playground
+/*
+Run time code - return 42
+602a60005260206000f3
+
+// Store 42 to memory
+mstore(p, v) - store v at memory p to p + 32
+
+PUSH1 0x2a
+PUSH1 0
+MSTORE
+
+// Return 32 bytes from memory
+return(p, s) - end execution and return data from memory p to p + s
+
+PUSH1 0x20
+PUSH1 0
+RETURN
+
+Creation code - return runtime code
+69602a60005260206000f3600052600a6016f3
+
+// Store run time code to memory
+PUSH10 0X602a60005260206000f3
+PUSH1 0
+MSTORE
+
+// Return 10 bytes from memory starting at offset 22
+PUSH1 0x0a
+PUSH1 0x16
+RETURN
+*/
+```
+
+## Teste no Remix
+
+- [Factory.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IEZhY3RvcnkgewogICAgZXZlbnQgTG9nKGFkZHJlc3MgYWRkcik7CgogICAgLy8gRGVwbG95cyBhIGNvbnRyYWN0IHRoYXQgYWx3YXlzIHJldHVybnMgNDIKICAgIGZ1bmN0aW9uIGRlcGxveSgpIGV4dGVybmFsIHsKICAgICAgICBieXRlcyBtZW1vcnkgYnl0ZWNvZGUgPSBoZXhcIjY5NjAyYTYwMDA1MjYwMjA2MDAwZjM2MDAwNTI2MDBhNjAxNmYzXCI7CiAgICAgICAgYWRkcmVzcyBhZGRyOwogICAgICAgIGFzc2VtYmx5IHsKICAgICAgICAgICAgLy8gY3JlYXRlKHZhbHVlLCBvZmZzZXQsIHNpemUpCiAgICAgICAgICAgIGFkZHIgOj0gY3JlYXRlKDAsIGFkZChieXRlY29kZSwgMHgyMCksIDB4MTMpCiAgICAgICAgfQogICAgICAgIHJlcXVpcmUoYWRkciAhPSBhZGRyZXNzKDApKTsKCiAgICAgICAgZW1pdCBMb2coYWRkcik7CiAgICB9Cn0KCmludGVyZmFjZSBJQ29udHJhY3QgewogICAgZnVuY3Rpb24gZ2V0TWVhbmluZ09mTGlmZSgpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAodWludCk7Cn0KCi8vIGh0dHBzOi8vd3d3LmV2bS5jb2Rlcy9wbGF5Z3JvdW5kCi8qClJ1biB0aW1lIGNvZGUgLSByZXR1cm4gNDIKNjAyYTYwMDA1MjYwMjA2MDAwZjMKCi8vIFN0b3JlIDQyIHRvIG1lbW9yeQptc3RvcmUocCwgdikgLSBzdG9yZSB2IGF0IG1lbW9yeSBwIHRvIHAgKyAzMgoKUFVTSDEgMHgyYQpQVVNIMSAwCk1TVE9SRQoKLy8gUmV0dXJuIDMyIGJ5dGVzIGZyb20gbWVtb3J5CnJldHVybihwLCBzKSAtIGVuZCBleGVjdXRpb24gYW5kIHJldHVybiBkYXRhIGZyb20gbWVtb3J5IHAgdG8gcCArIHMKClBVU0gxIDB4MjAKUFVTSDEgMApSRVRVUk4KCkNyZWF0aW9uIGNvZGUgLSByZXR1cm4gcnVudGltZSBjb2RlCjY5NjAyYTYwMDA1MjYwMjA2MDAwZjM2MDAwNTI2MDBhNjAxNmYzCgovLyBTdG9yZSBydW4gdGltZSBjb2RlIHRvIG1lbW9yeQpQVVNIMTAgMFg2MDJhNjAwMDUyNjAyMDYwMDBmMwpQVVNIMSAwCk1TVE9SRQoKLy8gUmV0dXJuIDEwIGJ5dGVzIGZyb20gbWVtb3J5IHN0YXJ0aW5nIGF0IG9mZnNldCAyMgpQVVNIMSAweDBhClBVU0gxIDB4MTYKUkVUVVJOCiov=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/contrato-proxy-minimo.md b/src/exemplos/aplicacoes/contrato-proxy-minimo.md
index ab80658..04aa504 100644
--- a/src/exemplos/aplicacoes/contrato-proxy-minimo.md
+++ b/src/exemplos/aplicacoes/contrato-proxy-minimo.md
@@ -1,10 +1,10 @@
# Contrato Proxy Mínimo
-Se você tem um contrato que será implantado múltiplas vezes, use o contrato proxy mínimo para implantá-los com baixo custo.
+Se você tem um contrato que será implantado várias vezes, use o contrato de proxy mínimo para implantá-los de forma econômica.
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
// código original
// https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol
@@ -30,7 +30,7 @@ contract MinimalProxy {
Lê os 32 bytes da memória começando no ponteiro armazenado em 0x40
No solidity, o slot 0x40 na memória é especial: ele contém o "ponteiro de memória livre"
- que aponta para o fim da memória corrente alocada.
+ que aponta para o fim da memória corrente alocada.
*/
let clone := mload(0x40)
// armazena 32 bytes de memória começando pelo "clone"
@@ -71,7 +71,11 @@ contract MinimalProxy {
// código começa pelo ponteiro armazenado no "clone"
// tamanho do código 0x37 (55 bytes)
result := create(0, clone, 0x37)
- }
+ }
}
}
```
+
+## Teste no Remix
+
+- [MinimalProxy.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8vIGNvZGlnbyBvcmlnaW5hbAovLyBodHRwczovL2dpdGh1Yi5jb20vb3B0aW9uYWxpdHkvY2xvbmUtZmFjdG9yeS9ibG9iL21hc3Rlci9jb250cmFjdHMvQ2xvbmVGYWN0b3J5LnNvbAoKY29udHJhY3QgTWluaW1hbFByb3h5IHsKICAgIGZ1bmN0aW9uIGNsb25lKGFkZHJlc3MgdGFyZ2V0KSBleHRlcm5hbCByZXR1cm5zIChhZGRyZXNzIHJlc3VsdCkgewogICAgICAgIC8vIGNvbnZlcnRlIG8gZW5kZXJlY28gcGFyYSAyMCBieXRlcwogICAgICAgIGJ5dGVzMjAgdGFyZ2V0Qnl0ZXMgPSBieXRlczIwKHRhcmdldCk7CgogICAgICAgIC8vIGNvZGlnbyByZWFsIC8vCiAgICAgICAgLy8gM2Q2MDJkODA2MDBhM2QzOTgxZjMzNjNkM2QzNzNkM2QzZDM2M2Q3M2JlYmViZWJlYmViZWJlYmViZWJlYmViZWJlYmViZWJlYmViZWJlYmU1YWY0M2Q4MjgwM2U5MDNkOTE2MDJiNTdmZDViZjMKCiAgICAgICAgLy8gY3JpYWNhbyBkbyBjb2RpZ28gLy8KICAgICAgICAvLyBjb3BpYSBvIGNvZGlnbyBkbyB0ZW1wbyBkZSBleGVjdWNhbyBuYSBtZW1vcmlhIGUgcmV0b3JuYSBlc3NlIGNvZGlnbwogICAgICAgIC8vIDNkNjAyZDgwNjAwYTNkMzk4MWYzCgogICAgICAgIC8vIGNvZGlnbyBlbSB0ZW1wbyBkZSBleGVjdWNhbyAvLwogICAgICAgIC8vIGNvZGlnbyBwYXJhIGRlbGVnYXRlY2FsbCBwYXJhIGVuZGVyZWNvCiAgICAgICAgLy8gMzYzZDNkMzczZDNkM2QzNjNkNzMgYWRkcmVzcyA1YWY0M2Q4MjgwM2U5MDNkOTE2MDJiNTdmZDViZjMKCiAgICAgICAgYXNzZW1ibHkgewogICAgICAgICAgICAvKgogICAgICAgICAgICBMZSBvcyAzMiBieXRlcyBkYSBtZW1vcmlhIGNvbWVjYW5kbyBubyBwb250ZWlybyBhcm1hemVuYWRvIGVtIDB4NDAKCiAgICAgICAgICAgIE5vIHNvbGlkaXR5LCBvIHNsb3QgMHg0MCBuYSBtZW1vcmlhIGUgZXNwZWNpYWw6IGVsZSBjb250ZW0gbyAicG9udGVpcm8gZGUgbWVtb3JpYSBsaXZyZSIKICAgICAgICAgICAgcXVlIGFwb250YSBwYXJhIG8gZmltIGRhIG1lbW9yaWEgY29ycmVudGUgYWxvY2FkYS4KICAgICAgICAgICAgKi8KICAgICAgICAgICAgbGV0IGNsb25lIDo9IG1sb2FkKDB4NDApCiAgICAgICAgICAgIC8vIGFybWF6ZW5hIDMyIGJ5dGVzIGRlIG1lbW9yaWEgY29tZWNhbmRvIHBlbG8gImNsb25lIgogICAgICAgICAgICBtc3RvcmUoCiAgICAgICAgICAgICAgICBjbG9uZSwKICAgICAgICAgICAgICAgIDB4M2Q2MDJkODA2MDBhM2QzOTgxZjMzNjNkM2QzNzNkM2QzZDM2M2Q3MzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAogICAgICAgICAgICApCgogICAgICAgICAgICAvKgogICAgICAgICAgICAgIHwgICAgICAgICAgICAgIDIwIGJ5dGVzICAgICAgICAgICAgICAgIHwKICAgICAgICAgICAgMHgzZDYwMmQ4MDYwMGEzZDM5ODFmMzM2M2QzZDM3M2QzZDNkMzYzZDczMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9pbnRlcgogICAgICAgICAgICAqLwogICAgICAgICAgICAvLyBhcm1hemVuYSAzMiBieXRlcyBkZSBtZW1vcmlhIGluaWNpYW5kbyBwZWxvICJjbG9uZSIgKyAyMCBieXRlcwogICAgICAgICAgICAvLyAweDE0ID0gMjAKICAgICAgICAgICAgbXN0b3JlKGFkZChjbG9uZSwgMHgxNCksIHRhcmdldEJ5dGVzKQoKICAgICAgICAgICAgLyoKICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgMjAgYnl0ZXMgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAyMCBieXRlcyAgICAgICAgICAgICAgfAogICAgICAgICAgICAweDNkNjAyZDgwNjAwYTNkMzk4MWYzMzYzZDNkMzczZDNkM2QzNjNkNzNiZWJlYmViZWJlYmViZWJlYmViZWJlYmViZWJlYmViZWJlYmViZWJlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBeCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb2ludGVyCiAgICAgICAgICAgICovCiAgICAgICAgICAgIC8vIGFybWF6ZW5hIDMyIGJ5dGVzIGRlIG1lbW9yaWEgaW5pY2lhbmRvIHBlbG8gImNsb25lIiArIDQwIGJ5dGVzCiAgICAgICAgICAgIC8vIDB4MjggPSA0MAogICAgICAgICAgICBtc3RvcmUoCiAgICAgICAgICAgICAgICBhZGQoY2xvbmUsIDB4MjgpLAogICAgICAgICAgICAgICAgMHg1YWY0M2Q4MjgwM2U5MDNkOTE2MDJiNTdmZDViZjMwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwCiAgICAgICAgICAgICkKCiAgICAgICAgICAgIC8qCiAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgIDIwIGJ5dGVzICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgMjAgYnl0ZXMgICAgICAgICAgICAgIHwgICAgICAgICAgIDE1IGJ5dGVzICAgICAgICAgIHwKICAgICAgICAgICAgMHgzZDYwMmQ4MDYwMGEzZDM5ODFmMzM2M2QzZDM3M2QzZDNkMzYzZDczYmViZWJlYmViZWJlYmViZWJlYmViZWJlYmViZWJlYmViZWJlYmViZTVhZjQzZDgyODAzZTkwM2Q5MTYwMmI1N2ZkNWJmMwogICAgICAgICAgICAqLwogICAgICAgICAgICAvLyBjcmlhIG5vdm8gY29udHJhdG8KICAgICAgICAgICAgLy8gZW52aWEgMCBFdGhlcgogICAgICAgICAgICAvLyBjb2RpZ28gY29tZWNhIHBlbG8gcG9udGVpcm8gYXJtYXplbmFkbyBubyAiY2xvbmUiCiAgICAgICAgICAgIC8vIHRhbWFuaG8gZG8gY29kaWdvIDB4MzcgKDU1IGJ5dGVzKQogICAgICAgICAgICByZXN1bHQgOj0gY3JlYXRlKDAsIGNsb25lLCAweDM3KQogICAgICAgIH0KICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/endereco-de-contrato-pre-computado-com-create2.md b/src/exemplos/aplicacoes/endereco-de-contrato-pre-computado-com-create2.md
index 000f20c..df5a1bf 100644
--- a/src/exemplos/aplicacoes/endereco-de-contrato-pre-computado-com-create2.md
+++ b/src/exemplos/aplicacoes/endereco-de-contrato-pre-computado-com-create2.md
@@ -1,23 +1,37 @@
# Endereço de Contrato pré-computado com Create2
-`Endereço de contrato pode ser pré-computado`, antes do contrato ser implantado usando `create2`
+O endereço do contrato pode ser pré-calculado, antes que o contrato seja implantado, usando `create2`
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
contract Factory {
+ // Retorna o endereço do contrato recém-implantado
+ function deploy(
+ address _owner,
+ uint _foo,
+ bytes32 _salt
+ ) public payable returns (address) {
+ // Esta sintaxe é uma nova maneira de invocar create2 sem assembly, você só precisa passar salt
+ // https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2
+ return address(new TestContract{salt: _salt}(_owner, _foo));
+ }
+}
+
+// Esta é a maneira mais antiga de fazer isso usando assembly
+contract FactoryAssembly {
event Deployed(address addr, uint salt);
- // 1. Pega o código de bytes do contrato a ser implantado
- // NOTA: _owner e _foo são argumentos do constructor TestContract's
+ // 1. Obtenha o bytecode do contrato a ser implantado
+ // NOTA: _owner e _foo são argumentos do constructor TestContract
function getBytecode(address _owner, uint _foo) public pure returns (bytes memory) {
bytes memory bytecode = type(TestContract).creationCode;
return abi.encodePacked(bytecode, abi.encode(_owner, _foo));
}
- // 2. Computa o endereço do contrato a ser implantado
+ // 2. Calcular o endereço do contrato a ser implantado
// NOTA: _salt é um número aleatório usado para criar um endereço
function getAddress(bytes memory bytecode, uint _salt)
public
@@ -28,14 +42,14 @@ contract Factory {
abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(bytecode))
);
- // NOTA: lança os últimos 20 bytes do hash para o endereço
+ // NOTA: converta os últimos 20 bytes de hash para o endereço
return address(uint160(uint(hash)));
}
// 3. Implanta o contrato
// NOTA:
- // Verifica o evento log Deployed que contém o endereço do TestContract implantado.
- // O endereço no log deve ser equivalente ao endereço computado de cima.
+ // Verifique o log de eventos Deployed que contém o endereço do TestContract implantado.
+ // O endereço no log deve ser igual ao endereço calculado acima.
function deploy(bytes memory bytecode, uint _salt) public payable {
address addr;
@@ -47,14 +61,14 @@ contract Factory {
e envia v wei
e retorna o novo endereço
onde novo endereço = primeiros 20 bytes de keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n)))
- s = valor big-endian 256-bit
+ s = valor big-endian 256-bit
*/
assembly {
addr := create2(
callvalue(), // wei enviado com a chamada atual
- // O código real começa depois de saltar os primeiros 32 bytes
+ //O código real começa após pular os primeiros 32 bytes
add(bytecode, 0x20),
- mload(bytecode), // Carrega o tamanho do código contido nos primeiros 32 bytes
+ mload(bytecode), // Carregar o tamanho do código contido nos primeiros 32 bytes
_salt // Salt dos argumentos de função
)
@@ -81,3 +95,7 @@ contract TestContract {
}
}
```
+
+## Teste no Remix
+
+- [Create2.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IEZhY3RvcnkgewogICAgLy8gUmV0b3JuYSBvIGVuZGVyZWNvIGRvIGNvbnRyYXRvIHJlY2VtLWltcGxhbnRhZG8KICAgIGZ1bmN0aW9uIGRlcGxveSgKICAgICAgICBhZGRyZXNzIF9vd25lciwKICAgICAgICB1aW50IF9mb28sCiAgICAgICAgYnl0ZXMzMiBfc2FsdAogICAgKSBwdWJsaWMgcGF5YWJsZSByZXR1cm5zIChhZGRyZXNzKSB7CiAgICAgICAgLy8gRXN0YSBzaW50YXhlIGUgdW1hIG5vdmEgbWFuZWlyYSBkZSBpbnZvY2FyIGNyZWF0ZTIgc2VtIGFzc2VtYmx5LCB2b2NlIHNvIHByZWNpc2EgcGFzc2FyIHNhbHQKICAgICAgICAvLyBodHRwczovL2RvY3Muc29saWRpdHlsYW5nLm9yZy9lbi9sYXRlc3QvY29udHJvbC1zdHJ1Y3R1cmVzLmh0bWwjc2FsdGVkLWNvbnRyYWN0LWNyZWF0aW9ucy1jcmVhdGUyCiAgICAgICAgcmV0dXJuIGFkZHJlc3MobmV3IFRlc3RDb250cmFjdHtzYWx0OiBfc2FsdH0oX293bmVyLCBfZm9vKSk7CiAgICB9Cn0KCi8vIEVzdGEgZSBhIG1hbmVpcmEgbWFpcyBhbnRpZ2EgZGUgZmF6ZXIgaXNzbyB1c2FuZG8gYXNzZW1ibHkKY29udHJhY3QgRmFjdG9yeUFzc2VtYmx5IHsKICAgIGV2ZW50IERlcGxveWVkKGFkZHJlc3MgYWRkciwgdWludCBzYWx0KTsKCiAgICAvLyAxLiBPYnRlbmhhIG8gYnl0ZWNvZGUgZG8gY29udHJhdG8gYSBzZXIgaW1wbGFudGFkbyAKICAgIC8vIE5PVEE6IF9vd25lciBlIF9mb28gc2FvIGFyZ3VtZW50b3MgZG8gY29uc3RydWN0b3IgVGVzdENvbnRyYWN0CiAgICBmdW5jdGlvbiBnZXRCeXRlY29kZShhZGRyZXNzIF9vd25lciwgdWludCBfZm9vKSBwdWJsaWMgcHVyZSByZXR1cm5zIChieXRlcyBtZW1vcnkpIHsKICAgICAgICBieXRlcyBtZW1vcnkgYnl0ZWNvZGUgPSB0eXBlKFRlc3RDb250cmFjdCkuY3JlYXRpb25Db2RlOwoKICAgICAgICByZXR1cm4gYWJpLmVuY29kZVBhY2tlZChieXRlY29kZSwgYWJpLmVuY29kZShfb3duZXIsIF9mb28pKTsKICAgIH0KCiAgICAvLyAyLiBDYWxjdWxhciBvIGVuZGVyZWNvIGRvIGNvbnRyYXRvIGEgc2VyIGltcGxhbnRhZG8KICAgIC8vIE5PVEE6IF9zYWx0IGUgdW0gbnVtZXJvIGFsZWF0b3JpbyB1c2FkbyBwYXJhIGNyaWFyIHVtIGVuZGVyZWNvCiAgICBmdW5jdGlvbiBnZXRBZGRyZXNzKGJ5dGVzIG1lbW9yeSBieXRlY29kZSwgdWludCBfc2FsdCkKICAgICAgICBwdWJsaWMKICAgICAgICB2aWV3CiAgICAgICAgcmV0dXJucyAoYWRkcmVzcykKICAgIHsKICAgICAgICBieXRlczMyIGhhc2ggPSBrZWNjYWsyNTYoCiAgICAgICAgICAgIGFiaS5lbmNvZGVQYWNrZWQoYnl0ZXMxKDB4ZmYpLCBhZGRyZXNzKHRoaXMpLCBfc2FsdCwga2VjY2FrMjU2KGJ5dGVjb2RlKSkKICAgICAgICApOwoKICAgICAgICAvLyBOT1RBOiBjb252ZXJ0YSBvcyB1bHRpbW9zIDIwIGJ5dGVzIGRlIGhhc2ggcGFyYSBvIGVuZGVyZWNvCiAgICAgICAgcmV0dXJuIGFkZHJlc3ModWludDE2MCh1aW50KGhhc2gpKSk7CiAgICB9CgogICAgLy8gMy4gSW1wbGFudGEgbyBjb250cmF0bwogICAgLy8gTk9UQToKICAgIC8vIFZlcmlmaXF1ZSBvIGxvZyBkZSBldmVudG9zIERlcGxveWVkIHF1ZSBjb250ZW0gbyBlbmRlcmVjbyBkbyBUZXN0Q29udHJhY3QgaW1wbGFudGFkby4KICAgIC8vIE8gZW5kZXJlY28gbm8gbG9nIGRldmUgc2VyIGlndWFsIGFvIGVuZGVyZWNvIGNhbGN1bGFkbyBhY2ltYS4KICAgIGZ1bmN0aW9uIGRlcGxveShieXRlcyBtZW1vcnkgYnl0ZWNvZGUsIHVpbnQgX3NhbHQpIHB1YmxpYyBwYXlhYmxlIHsKICAgICAgICBhZGRyZXNzIGFkZHI7CgogICAgICAgIC8qCiAgICAgICAgTk9UQTogQ29tbyBjcmlhciBjcmVhdGUyCgogICAgICAgIGNyZWF0ZTIodiwgcCwgbiwgcykKICAgICAgICBjcmlhIHVtIG5vdm8gY29udHJhdG8gY29tIGNvZGlnbyBuYSBtZW1vcmlhIHAgcGFyYSBwICsgbgogICAgICAgIGUgZW52aWEgdiB3ZWkKICAgICAgICBlIHJldG9ybmEgbyBub3ZvIGVuZGVyZWNvCiAgICAgICAgb25kZSBub3ZvIGVuZGVyZWNvID0gcHJpbWVpcm9zIDIwIGJ5dGVzIGRlIGtlY2NhazI1NigweGZmICsgYWRkcmVzcyh0aGlzKSArIHMgKyBrZWNjYWsyNTYobWVtW3A/KHArbikpKQogICAgICAgICAgICAgIHMgPSB2YWxvciBiaWctZW5kaWFuIDI1Ni1iaXQKICAgICAgICAqLwogICAgICAgIGFzc2VtYmx5IHsKICAgICAgICAgICAgYWRkciA6PSBjcmVhdGUyKAogICAgICAgICAgICAgICAgY2FsbHZhbHVlKCksIC8vIHdlaSBlbnZpYWRvIGNvbSBhIGNoYW1hZGEgYXR1YWwKICAgICAgICAgICAgICAgIC8vTyBjb2RpZ28gcmVhbCBjb21lY2EgYXBvcyBwdWxhciBvcyBwcmltZWlyb3MgMzIgYnl0ZXMKICAgICAgICAgICAgICAgIGFkZChieXRlY29kZSwgMHgyMCksCiAgICAgICAgICAgICAgICBtbG9hZChieXRlY29kZSksIC8vIENhcnJlZ2FyIG8gdGFtYW5obyBkbyBjb2RpZ28gY29udGlkbyBub3MgcHJpbWVpcm9zIDMyIGJ5dGVzCiAgICAgICAgICAgICAgICBfc2FsdCAvLyBTYWx0IGRvcyBhcmd1bWVudG9zIGRlIGZ1bmNhbwogICAgICAgICAgICApCgogICAgICAgICAgICBpZiBpc3plcm8oZXh0Y29kZXNpemUoYWRkcikpIHsKICAgICAgICAgICAgICAgIHJldmVydCgwLCAwKQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBlbWl0IERlcGxveWVkKGFkZHIsIF9zYWx0KTsKICAgIH0KfQoKY29udHJhY3QgVGVzdENvbnRyYWN0IHsKICAgIGFkZHJlc3MgcHVibGljIG93bmVyOwogICAgdWludCBwdWJsaWMgZm9vOwoKICAgIGNvbnN0cnVjdG9yKGFkZHJlc3MgX293bmVyLCB1aW50IF9mb28pIHBheWFibGUgewogICAgICAgIG93bmVyID0gX293bmVyOwogICAgICAgIGZvbyA9IF9mb287CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0QmFsYW5jZSgpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQpIHsKICAgICAgICByZXR1cm4gYWRkcmVzcyh0aGlzKS5iYWxhbmNlOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/erc1155.md b/src/exemplos/aplicacoes/erc1155.md
new file mode 100644
index 0000000..cd4afe1
--- /dev/null
+++ b/src/exemplos/aplicacoes/erc1155.md
@@ -0,0 +1,282 @@
+# ERC1155
+
+Exemplo de um contrato ERC1155.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+interface IERC1155 {
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 id,
+ uint256 value,
+ bytes calldata data
+ ) external;
+
+ function safeBatchTransferFrom(
+ address from,
+ address to,
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) external;
+
+ function balanceOf(address owner, uint256 id) external view returns (uint256);
+
+ function balanceOfBatch(
+ address[] calldata owners,
+ uint256[] calldata ids
+ ) external view returns (uint256[] memory);
+
+ function setApprovalForAll(address operator, bool approved) external;
+
+ function isApprovedForAll(
+ address owner,
+ address operator
+ ) external view returns (bool);
+}
+
+interface IERC1155TokenReceiver {
+ function onERC1155Received(
+ address operator,
+ address from,
+ uint256 id,
+ uint256 value,
+ bytes calldata data
+ ) external returns (bytes4);
+
+ function onERC1155BatchReceived(
+ address operator,
+ address from,
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) external returns (bytes4);
+}
+
+contract ERC1155 is IERC1155 {
+ event TransferSingle(
+ address indexed operator,
+ address indexed from,
+ address indexed to,
+ uint256 id,
+ uint256 value
+ );
+ event TransferBatch(
+ address indexed operator,
+ address indexed from,
+ address indexed to,
+ uint256[] ids,
+ uint256[] values
+ );
+ event ApprovalForAll(
+ address indexed owner,
+ address indexed operator,
+ bool approved
+ );
+ event URI(string value, uint256 indexed id);
+
+ // owner => id => balance
+ mapping(address => mapping(uint256 => uint256)) public balanceOf;
+ // owner => operator => approved
+ mapping(address => mapping(address => bool)) public isApprovedForAll;
+
+ function balanceOfBatch(
+ address[] calldata owners,
+ uint256[] calldata ids
+ ) external view returns (uint256[] memory balances) {
+ require(owners.length == ids.length, "owners length != ids length");
+
+ balances = new uint[](owners.length);
+
+ unchecked {
+ for (uint256 i = 0; i < owners.length; i++) {
+ balances[i] = balanceOf[owners[i]][ids[i]];
+ }
+ }
+ }
+
+ function setApprovalForAll(address operator, bool approved) external {
+ isApprovedForAll[msg.sender][operator] = approved;
+ emit ApprovalForAll(msg.sender, operator, approved);
+ }
+
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 id,
+ uint256 value,
+ bytes calldata data
+ ) external {
+ require(
+ msg.sender == from || isApprovedForAll[from][msg.sender],
+ "not approved"
+ );
+ require(to != address(0), "to = 0 address");
+
+ balanceOf[from][id] -= value;
+ balanceOf[to][id] += value;
+
+ emit TransferSingle(msg.sender, from, to, id, value);
+
+ if (to.code.length > 0) {
+ require(
+ IERC1155TokenReceiver(to).onERC1155Received(
+ msg.sender,
+ from,
+ id,
+ value,
+ data
+ ) == IERC1155TokenReceiver.onERC1155Received.selector,
+ "unsafe transfer"
+ );
+ }
+ }
+
+ function safeBatchTransferFrom(
+ address from,
+ address to,
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) external {
+ require(
+ msg.sender == from || isApprovedForAll[from][msg.sender],
+ "not approved"
+ );
+ require(to != address(0), "to = 0 address");
+ require(ids.length == values.length, "ids length != values length");
+
+ for (uint256 i = 0; i < ids.length; i++) {
+ balanceOf[from][ids[i]] -= values[i];
+ balanceOf[to][ids[i]] += values[i];
+ }
+
+ emit TransferBatch(msg.sender, from, to, ids, values);
+
+ if (to.code.length > 0) {
+ require(
+ IERC1155TokenReceiver(to).onERC1155BatchReceived(
+ msg.sender,
+ from,
+ ids,
+ values,
+ data
+ ) == IERC1155TokenReceiver.onERC1155BatchReceived.selector,
+ "unsafe transfer"
+ );
+ }
+ }
+
+ // ERC165
+ function supportsInterface(bytes4 interfaceId) external view returns (bool) {
+ return
+ interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
+ interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
+ interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
+ }
+
+ // ERC1155 Metadata URI
+ function uri(uint256 id) public view virtual returns (string memory) {}
+
+ // Internal functions
+ function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
+ require(to != address(0), "to = 0 address");
+
+ balanceOf[to][id] += value;
+
+ emit TransferSingle(msg.sender, address(0), to, id, value);
+
+ if (to.code.length > 0) {
+ require(
+ IERC1155TokenReceiver(to).onERC1155Received(
+ msg.sender,
+ address(0),
+ id,
+ value,
+ data
+ ) == IERC1155TokenReceiver.onERC1155Received.selector,
+ "unsafe transfer"
+ );
+ }
+ }
+
+ function _batchMint(
+ address to,
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) internal {
+ require(to != address(0), "to = 0 address");
+ require(ids.length == values.length, "ids length != values length");
+
+ for (uint256 i = 0; i < ids.length; i++) {
+ balanceOf[to][ids[i]] += values[i];
+ }
+
+ emit TransferBatch(msg.sender, address(0), to, ids, values);
+
+ if (to.code.length > 0) {
+ require(
+ IERC1155TokenReceiver(to).onERC1155BatchReceived(
+ msg.sender,
+ address(0),
+ ids,
+ values,
+ data
+ ) == IERC1155TokenReceiver.onERC1155BatchReceived.selector,
+ "unsafe transfer"
+ );
+ }
+ }
+
+ function _burn(address from, uint256 id, uint256 value) internal {
+ require(from != address(0), "from = 0 address");
+ balanceOf[from][id] -= value;
+ emit TransferSingle(msg.sender, from, address(0), id, value);
+ }
+
+ function _batchBurn(
+ address from,
+ uint256[] calldata ids,
+ uint256[] calldata values
+ ) internal {
+ require(from != address(0), "from = 0 address");
+ require(ids.length == values.length, "ids length != values length");
+
+ for (uint256 i = 0; i < ids.length; i++) {
+ balanceOf[from][ids[i]] -= values[i];
+ }
+
+ emit TransferBatch(msg.sender, from, address(0), ids, values);
+ }
+}
+
+contract MyMultiToken is ERC1155 {
+ function mint(uint256 id, uint256 value, bytes memory data) external {
+ _mint(msg.sender, id, value, data);
+ }
+
+ function batchMint(
+ uint256[] calldata ids,
+ uint256[] calldata values,
+ bytes calldata data
+ ) external {
+ _batchMint(msg.sender, ids, values, data);
+ }
+
+ function burn(uint256 id, uint256 value) external {
+ _burn(msg.sender, id, value);
+ }
+
+ function batchBurn(uint256[] calldata ids, uint256[] calldata values) external {
+ _batchBurn(msg.sender, ids, values);
+ }
+}
+```
+
+## Teste no Remix
+
+- [ERC1155.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmludGVyZmFjZSBJRVJDMTE1NSB7CiAgICBmdW5jdGlvbiBzYWZlVHJhbnNmZXJGcm9tKAogICAgICAgIGFkZHJlc3MgZnJvbSwKICAgICAgICBhZGRyZXNzIHRvLAogICAgICAgIHVpbnQyNTYgaWQsCiAgICAgICAgdWludDI1NiB2YWx1ZSwKICAgICAgICBieXRlcyBjYWxsZGF0YSBkYXRhCiAgICApIGV4dGVybmFsOwoKICAgIGZ1bmN0aW9uIHNhZmVCYXRjaFRyYW5zZmVyRnJvbSgKICAgICAgICBhZGRyZXNzIGZyb20sCiAgICAgICAgYWRkcmVzcyB0bywKICAgICAgICB1aW50MjU2W10gY2FsbGRhdGEgaWRzLAogICAgICAgIHVpbnQyNTZbXSBjYWxsZGF0YSB2YWx1ZXMsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgZGF0YQogICAgKSBleHRlcm5hbDsKCiAgICBmdW5jdGlvbiBiYWxhbmNlT2YoYWRkcmVzcyBvd25lciwgdWludDI1NiBpZCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zICh1aW50MjU2KTsKCiAgICBmdW5jdGlvbiBiYWxhbmNlT2ZCYXRjaCgKICAgICAgICBhZGRyZXNzW10gY2FsbGRhdGEgb3duZXJzLAogICAgICAgIHVpbnQyNTZbXSBjYWxsZGF0YSBpZHMKICAgICkgZXh0ZXJuYWwgdmlldyByZXR1cm5zICh1aW50MjU2W10gbWVtb3J5KTsKCiAgICBmdW5jdGlvbiBzZXRBcHByb3ZhbEZvckFsbChhZGRyZXNzIG9wZXJhdG9yLCBib29sIGFwcHJvdmVkKSBleHRlcm5hbDsKCiAgICBmdW5jdGlvbiBpc0FwcHJvdmVkRm9yQWxsKAogICAgICAgIGFkZHJlc3Mgb3duZXIsCiAgICAgICAgYWRkcmVzcyBvcGVyYXRvcgogICAgKSBleHRlcm5hbCB2aWV3IHJldHVybnMgKGJvb2wpOwp9CgppbnRlcmZhY2UgSUVSQzExNTVUb2tlblJlY2VpdmVyIHsKICAgIGZ1bmN0aW9uIG9uRVJDMTE1NVJlY2VpdmVkKAogICAgICAgIGFkZHJlc3Mgb3BlcmF0b3IsCiAgICAgICAgYWRkcmVzcyBmcm9tLAogICAgICAgIHVpbnQyNTYgaWQsCiAgICAgICAgdWludDI1NiB2YWx1ZSwKICAgICAgICBieXRlcyBjYWxsZGF0YSBkYXRhCiAgICApIGV4dGVybmFsIHJldHVybnMgKGJ5dGVzNCk7CgogICAgZnVuY3Rpb24gb25FUkMxMTU1QmF0Y2hSZWNlaXZlZCgKICAgICAgICBhZGRyZXNzIG9wZXJhdG9yLAogICAgICAgIGFkZHJlc3MgZnJvbSwKICAgICAgICB1aW50MjU2W10gY2FsbGRhdGEgaWRzLAogICAgICAgIHVpbnQyNTZbXSBjYWxsZGF0YSB2YWx1ZXMsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgZGF0YQogICAgKSBleHRlcm5hbCByZXR1cm5zIChieXRlczQpOwp9Cgpjb250cmFjdCBFUkMxMTU1IGlzIElFUkMxMTU1IHsKICAgIGV2ZW50IFRyYW5zZmVyU2luZ2xlKAogICAgICAgIGFkZHJlc3MgaW5kZXhlZCBvcGVyYXRvciwKICAgICAgICBhZGRyZXNzIGluZGV4ZWQgZnJvbSwKICAgICAgICBhZGRyZXNzIGluZGV4ZWQgdG8sCiAgICAgICAgdWludDI1NiBpZCwKICAgICAgICB1aW50MjU2IHZhbHVlCiAgICApOwogICAgZXZlbnQgVHJhbnNmZXJCYXRjaCgKICAgICAgICBhZGRyZXNzIGluZGV4ZWQgb3BlcmF0b3IsCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIGZyb20sCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIHRvLAogICAgICAgIHVpbnQyNTZbXSBpZHMsCiAgICAgICAgdWludDI1NltdIHZhbHVlcwogICAgKTsKICAgIGV2ZW50IEFwcHJvdmFsRm9yQWxsKAogICAgICAgIGFkZHJlc3MgaW5kZXhlZCBvd25lciwKICAgICAgICBhZGRyZXNzIGluZGV4ZWQgb3BlcmF0b3IsCiAgICAgICAgYm9vbCBhcHByb3ZlZAogICAgKTsKICAgIGV2ZW50IFVSSShzdHJpbmcgdmFsdWUsIHVpbnQyNTYgaW5kZXhlZCBpZCk7CgogICAgLy8gb3duZXIgPT4gaWQgPT4gYmFsYW5jZQogICAgbWFwcGluZyhhZGRyZXNzID0+IG1hcHBpbmcodWludDI1NiA9PiB1aW50MjU2KSkgcHVibGljIGJhbGFuY2VPZjsKICAgIC8vIG93bmVyID0+IG9wZXJhdG9yID0+IGFwcHJvdmVkCiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gbWFwcGluZyhhZGRyZXNzID0+IGJvb2wpKSBwdWJsaWMgaXNBcHByb3ZlZEZvckFsbDsKCiAgICBmdW5jdGlvbiBiYWxhbmNlT2ZCYXRjaCgKICAgICAgICBhZGRyZXNzW10gY2FsbGRhdGEgb3duZXJzLAogICAgICAgIHVpbnQyNTZbXSBjYWxsZGF0YSBpZHMKICAgICkgZXh0ZXJuYWwgdmlldyByZXR1cm5zICh1aW50MjU2W10gbWVtb3J5IGJhbGFuY2VzKSB7CiAgICAgICAgcmVxdWlyZShvd25lcnMubGVuZ3RoID09IGlkcy5sZW5ndGgsICJvd25lcnMgbGVuZ3RoICE9IGlkcyBsZW5ndGgiKTsKCiAgICAgICAgYmFsYW5jZXMgPSBuZXcgdWludFtdKG93bmVycy5sZW5ndGgpOwoKICAgICAgICB1bmNoZWNrZWQgewogICAgICAgICAgICBmb3IgKHVpbnQyNTYgaSA9IDA7IGkgPCBvd25lcnMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgICAgIGJhbGFuY2VzW2ldID0gYmFsYW5jZU9mW293bmVyc1tpXV1baWRzW2ldXTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBzZXRBcHByb3ZhbEZvckFsbChhZGRyZXNzIG9wZXJhdG9yLCBib29sIGFwcHJvdmVkKSBleHRlcm5hbCB7CiAgICAgICAgaXNBcHByb3ZlZEZvckFsbFttc2cuc2VuZGVyXVtvcGVyYXRvcl0gPSBhcHByb3ZlZDsKICAgICAgICBlbWl0IEFwcHJvdmFsRm9yQWxsKG1zZy5zZW5kZXIsIG9wZXJhdG9yLCBhcHByb3ZlZCk7CiAgICB9CgogICAgZnVuY3Rpb24gc2FmZVRyYW5zZmVyRnJvbSgKICAgICAgICBhZGRyZXNzIGZyb20sCiAgICAgICAgYWRkcmVzcyB0bywKICAgICAgICB1aW50MjU2IGlkLAogICAgICAgIHVpbnQyNTYgdmFsdWUsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgZGF0YQogICAgKSBleHRlcm5hbCB7CiAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgbXNnLnNlbmRlciA9PSBmcm9tIHx8IGlzQXBwcm92ZWRGb3JBbGxbZnJvbV1bbXNnLnNlbmRlcl0sCiAgICAgICAgICAgICJub3QgYXBwcm92ZWQiCiAgICAgICAgKTsKICAgICAgICByZXF1aXJlKHRvICE9IGFkZHJlc3MoMCksICJ0byA9IDAgYWRkcmVzcyIpOwoKICAgICAgICBiYWxhbmNlT2ZbZnJvbV1baWRdIC09IHZhbHVlOwogICAgICAgIGJhbGFuY2VPZlt0b11baWRdICs9IHZhbHVlOwoKICAgICAgICBlbWl0IFRyYW5zZmVyU2luZ2xlKG1zZy5zZW5kZXIsIGZyb20sIHRvLCBpZCwgdmFsdWUpOwoKICAgICAgICBpZiAodG8uY29kZS5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgIHJlcXVpcmUoCiAgICAgICAgICAgICAgICBJRVJDMTE1NVRva2VuUmVjZWl2ZXIodG8pLm9uRVJDMTE1NVJlY2VpdmVkKAogICAgICAgICAgICAgICAgICAgIG1zZy5zZW5kZXIsCiAgICAgICAgICAgICAgICAgICAgZnJvbSwKICAgICAgICAgICAgICAgICAgICBpZCwKICAgICAgICAgICAgICAgICAgICB2YWx1ZSwKICAgICAgICAgICAgICAgICAgICBkYXRhCiAgICAgICAgICAgICAgICApID09IElFUkMxMTU1VG9rZW5SZWNlaXZlci5vbkVSQzExNTVSZWNlaXZlZC5zZWxlY3RvciwKICAgICAgICAgICAgICAgICJ1bnNhZmUgdHJhbnNmZXIiCiAgICAgICAgICAgICk7CiAgICAgICAgfQogICAgfQoKICAgIGZ1bmN0aW9uIHNhZmVCYXRjaFRyYW5zZmVyRnJvbSgKICAgICAgICBhZGRyZXNzIGZyb20sCiAgICAgICAgYWRkcmVzcyB0bywKICAgICAgICB1aW50MjU2W10gY2FsbGRhdGEgaWRzLAogICAgICAgIHVpbnQyNTZbXSBjYWxsZGF0YSB2YWx1ZXMsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgZGF0YQogICAgKSBleHRlcm5hbCB7CiAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgbXNnLnNlbmRlciA9PSBmcm9tIHx8IGlzQXBwcm92ZWRGb3JBbGxbZnJvbV1bbXNnLnNlbmRlcl0sCiAgICAgICAgICAgICJub3QgYXBwcm92ZWQiCiAgICAgICAgKTsKICAgICAgICByZXF1aXJlKHRvICE9IGFkZHJlc3MoMCksICJ0byA9IDAgYWRkcmVzcyIpOwogICAgICAgIHJlcXVpcmUoaWRzLmxlbmd0aCA9PSB2YWx1ZXMubGVuZ3RoLCAiaWRzIGxlbmd0aCAhPSB2YWx1ZXMgbGVuZ3RoIik7CgogICAgICAgIGZvciAodWludDI1NiBpID0gMDsgaSA8IGlkcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICBiYWxhbmNlT2ZbZnJvbV1baWRzW2ldXSAtPSB2YWx1ZXNbaV07CiAgICAgICAgICAgIGJhbGFuY2VPZlt0b11baWRzW2ldXSArPSB2YWx1ZXNbaV07CiAgICAgICAgfQoKICAgICAgICBlbWl0IFRyYW5zZmVyQmF0Y2gobXNnLnNlbmRlciwgZnJvbSwgdG8sIGlkcywgdmFsdWVzKTsKCiAgICAgICAgaWYgKHRvLmNvZGUubGVuZ3RoID4gMCkgewogICAgICAgICAgICByZXF1aXJlKAogICAgICAgICAgICAgICAgSUVSQzExNTVUb2tlblJlY2VpdmVyKHRvKS5vbkVSQzExNTVCYXRjaFJlY2VpdmVkKAogICAgICAgICAgICAgICAgICAgIG1zZy5zZW5kZXIsCiAgICAgICAgICAgICAgICAgICAgZnJvbSwKICAgICAgICAgICAgICAgICAgICBpZHMsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzLAogICAgICAgICAgICAgICAgICAgIGRhdGEKICAgICAgICAgICAgICAgICkgPT0gSUVSQzExNTVUb2tlblJlY2VpdmVyLm9uRVJDMTE1NUJhdGNoUmVjZWl2ZWQuc2VsZWN0b3IsCiAgICAgICAgICAgICAgICAidW5zYWZlIHRyYW5zZmVyIgogICAgICAgICAgICApOwogICAgICAgIH0KICAgIH0KCiAgICAvLyBFUkMxNjUKICAgIGZ1bmN0aW9uIHN1cHBvcnRzSW50ZXJmYWNlKGJ5dGVzNCBpbnRlcmZhY2VJZCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChib29sKSB7CiAgICAgICAgcmV0dXJuCiAgICAgICAgICAgIGludGVyZmFjZUlkID09IDB4MDFmZmM5YTcgfHwgLy8gRVJDMTY1IEludGVyZmFjZSBJRCBmb3IgRVJDMTY1CiAgICAgICAgICAgIGludGVyZmFjZUlkID09IDB4ZDliNjdhMjYgfHwgLy8gRVJDMTY1IEludGVyZmFjZSBJRCBmb3IgRVJDMTE1NQogICAgICAgICAgICBpbnRlcmZhY2VJZCA9PSAweDBlODkzNDFjOyAvLyBFUkMxNjUgSW50ZXJmYWNlIElEIGZvciBFUkMxMTU1TWV0YWRhdGFVUkkKICAgIH0KCiAgICAvLyBFUkMxMTU1IE1ldGFkYXRhIFVSSQogICAgZnVuY3Rpb24gdXJpKHVpbnQyNTYgaWQpIHB1YmxpYyB2aWV3IHZpcnR1YWwgcmV0dXJucyAoc3RyaW5nIG1lbW9yeSkge30KCiAgICAvLyBJbnRlcm5hbCBmdW5jdGlvbnMKICAgIGZ1bmN0aW9uIF9taW50KGFkZHJlc3MgdG8sIHVpbnQyNTYgaWQsIHVpbnQyNTYgdmFsdWUsIGJ5dGVzIG1lbW9yeSBkYXRhKSBpbnRlcm5hbCB7CiAgICAgICAgcmVxdWlyZSh0byAhPSBhZGRyZXNzKDApLCAidG8gPSAwIGFkZHJlc3MiKTsKCiAgICAgICAgYmFsYW5jZU9mW3RvXVtpZF0gKz0gdmFsdWU7CgogICAgICAgIGVtaXQgVHJhbnNmZXJTaW5nbGUobXNnLnNlbmRlciwgYWRkcmVzcygwKSwgdG8sIGlkLCB2YWx1ZSk7CgogICAgICAgIGlmICh0by5jb2RlLmxlbmd0aCA+IDApIHsKICAgICAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgICAgIElFUkMxMTU1VG9rZW5SZWNlaXZlcih0bykub25FUkMxMTU1UmVjZWl2ZWQoCiAgICAgICAgICAgICAgICAgICAgbXNnLnNlbmRlciwKICAgICAgICAgICAgICAgICAgICBhZGRyZXNzKDApLAogICAgICAgICAgICAgICAgICAgIGlkLAogICAgICAgICAgICAgICAgICAgIHZhbHVlLAogICAgICAgICAgICAgICAgICAgIGRhdGEKICAgICAgICAgICAgICAgICkgPT0gSUVSQzExNTVUb2tlblJlY2VpdmVyLm9uRVJDMTE1NVJlY2VpdmVkLnNlbGVjdG9yLAogICAgICAgICAgICAgICAgInVuc2FmZSB0cmFuc2ZlciIKICAgICAgICAgICAgKTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gX2JhdGNoTWludCgKICAgICAgICBhZGRyZXNzIHRvLAogICAgICAgIHVpbnQyNTZbXSBjYWxsZGF0YSBpZHMsCiAgICAgICAgdWludDI1NltdIGNhbGxkYXRhIHZhbHVlcywKICAgICAgICBieXRlcyBjYWxsZGF0YSBkYXRhCiAgICApIGludGVybmFsIHsKICAgICAgICByZXF1aXJlKHRvICE9IGFkZHJlc3MoMCksICJ0byA9IDAgYWRkcmVzcyIpOwogICAgICAgIHJlcXVpcmUoaWRzLmxlbmd0aCA9PSB2YWx1ZXMubGVuZ3RoLCAiaWRzIGxlbmd0aCAhPSB2YWx1ZXMgbGVuZ3RoIik7CgogICAgICAgIGZvciAodWludDI1NiBpID0gMDsgaSA8IGlkcy5sZW5ndGg7IGkrKykgewogICAgICAgICAgICBiYWxhbmNlT2ZbdG9dW2lkc1tpXV0gKz0gdmFsdWVzW2ldOwogICAgICAgIH0KCiAgICAgICAgZW1pdCBUcmFuc2ZlckJhdGNoKG1zZy5zZW5kZXIsIGFkZHJlc3MoMCksIHRvLCBpZHMsIHZhbHVlcyk7CgogICAgICAgIGlmICh0by5jb2RlLmxlbmd0aCA+IDApIHsKICAgICAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgICAgIElFUkMxMTU1VG9rZW5SZWNlaXZlcih0bykub25FUkMxMTU1QmF0Y2hSZWNlaXZlZCgKICAgICAgICAgICAgICAgICAgICBtc2cuc2VuZGVyLAogICAgICAgICAgICAgICAgICAgIGFkZHJlc3MoMCksCiAgICAgICAgICAgICAgICAgICAgaWRzLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcywKICAgICAgICAgICAgICAgICAgICBkYXRhCiAgICAgICAgICAgICAgICApID09IElFUkMxMTU1VG9rZW5SZWNlaXZlci5vbkVSQzExNTVCYXRjaFJlY2VpdmVkLnNlbGVjdG9yLAogICAgICAgICAgICAgICAgInVuc2FmZSB0cmFuc2ZlciIKICAgICAgICAgICAgKTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gX2J1cm4oYWRkcmVzcyBmcm9tLCB1aW50MjU2IGlkLCB1aW50MjU2IHZhbHVlKSBpbnRlcm5hbCB7CiAgICAgICAgcmVxdWlyZShmcm9tICE9IGFkZHJlc3MoMCksICJmcm9tID0gMCBhZGRyZXNzIik7CiAgICAgICAgYmFsYW5jZU9mW2Zyb21dW2lkXSAtPSB2YWx1ZTsKICAgICAgICBlbWl0IFRyYW5zZmVyU2luZ2xlKG1zZy5zZW5kZXIsIGZyb20sIGFkZHJlc3MoMCksIGlkLCB2YWx1ZSk7CiAgICB9CgogICAgZnVuY3Rpb24gX2JhdGNoQnVybigKICAgICAgICBhZGRyZXNzIGZyb20sCiAgICAgICAgdWludDI1NltdIGNhbGxkYXRhIGlkcywKICAgICAgICB1aW50MjU2W10gY2FsbGRhdGEgdmFsdWVzCiAgICApIGludGVybmFsIHsKICAgICAgICByZXF1aXJlKGZyb20gIT0gYWRkcmVzcygwKSwgImZyb20gPSAwIGFkZHJlc3MiKTsKICAgICAgICByZXF1aXJlKGlkcy5sZW5ndGggPT0gdmFsdWVzLmxlbmd0aCwgImlkcyBsZW5ndGggIT0gdmFsdWVzIGxlbmd0aCIpOwoKICAgICAgICBmb3IgKHVpbnQyNTYgaSA9IDA7IGkgPCBpZHMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgYmFsYW5jZU9mW2Zyb21dW2lkc1tpXV0gLT0gdmFsdWVzW2ldOwogICAgICAgIH0KCiAgICAgICAgZW1pdCBUcmFuc2ZlckJhdGNoKG1zZy5zZW5kZXIsIGZyb20sIGFkZHJlc3MoMCksIGlkcywgdmFsdWVzKTsKICAgIH0KfQoKY29udHJhY3QgTXlNdWx0aVRva2VuIGlzIEVSQzExNTUgewogICAgZnVuY3Rpb24gbWludCh1aW50MjU2IGlkLCB1aW50MjU2IHZhbHVlLCBieXRlcyBtZW1vcnkgZGF0YSkgZXh0ZXJuYWwgewogICAgICAgIF9taW50KG1zZy5zZW5kZXIsIGlkLCB2YWx1ZSwgZGF0YSk7CiAgICB9CgogICAgZnVuY3Rpb24gYmF0Y2hNaW50KAogICAgICAgIHVpbnQyNTZbXSBjYWxsZGF0YSBpZHMsCiAgICAgICAgdWludDI1NltdIGNhbGxkYXRhIHZhbHVlcywKICAgICAgICBieXRlcyBjYWxsZGF0YSBkYXRhCiAgICApIGV4dGVybmFsIHsKICAgICAgICBfYmF0Y2hNaW50KG1zZy5zZW5kZXIsIGlkcywgdmFsdWVzLCBkYXRhKTsKICAgIH0KCiAgICBmdW5jdGlvbiBidXJuKHVpbnQyNTYgaWQsIHVpbnQyNTYgdmFsdWUpIGV4dGVybmFsIHsKICAgICAgICBfYnVybihtc2cuc2VuZGVyLCBpZCwgdmFsdWUpOwogICAgfQoKICAgIGZ1bmN0aW9uIGJhdGNoQnVybih1aW50MjU2W10gY2FsbGRhdGEgaWRzLCB1aW50MjU2W10gY2FsbGRhdGEgdmFsdWVzKSBleHRlcm5hbCB7CiAgICAgICAgX2JhdGNoQnVybihtc2cuc2VuZGVyLCBpZHMsIHZhbHVlcyk7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/erc20.md b/src/exemplos/aplicacoes/erc20.md
index a9d9f0d..137aacf 100644
--- a/src/exemplos/aplicacoes/erc20.md
+++ b/src/exemplos/aplicacoes/erc20.md
@@ -1,17 +1,17 @@
# ERC20
-`Todo contrato que segue o` [ERC20 standard](https://eips.ethereum.org/EIPS/eip-20) é um token ERC20.
+Todo contrato que segue o [ERC20 standard](https://eips.ethereum.org/EIPS/eip-20) é um token ERC20.
Tokens ERC20 fornecem funcionalidades para
-* transferir tokens
-* permitir que outros transfiram tokens em nome do titular do token
+- transferir tokens
+- permitir que outros transfiram tokens em nome do titular do token
Eis aqui a interface para ERC20.
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol
interface IERC20 {
@@ -26,9 +26,9 @@ interface IERC20 {
function approve(address spender, uint amount) external returns (bool);
function transferFrom(
- address sender,
- address recipient,
- uint amount
+ address remetente,
+ address destinatario,
+ uint quantidade
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
@@ -36,6 +36,61 @@ interface IERC20 {
}
```
+Exemplo de um contrato de token ERC20.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+import "./IERC20.sol";
+
+contract ERC20 is IERC20 {
+ uint public totalSupply;
+ mapping(address => uint) public balanceOf;
+ mapping(address => mapping(address => uint)) public allowance;
+ string public name = "Solidity by Example";
+ string public symbol = "SOLBYEX";
+ uint8 public decimals = 18;
+
+ function transfer(address recipient, uint amount) external returns (bool) {
+ balanceOf[msg.sender] -= amount;
+ balanceOf[recipient] += amount;
+ emit Transfer(msg.sender, recipient, amount);
+ return true;
+ }
+
+ function approve(address spender, uint amount) external returns (bool) {
+ allowance[msg.sender][spender] = amount;
+ emit Approval(msg.sender, spender, amount);
+ return true;
+ }
+
+ function transferFrom(
+ address remetente,
+ address destinatario,
+ uint quantidade
+ ) external returns (bool) {
+ allowance[sender][msg.sender] -= amount;
+ balanceOf[sender] -= amount;
+ balanceOf[recipient] += amount;
+ emit Transfer(sender, recipient, amount);
+ return true;
+ }
+
+ function mint(uint amount) external {
+ balanceOf[msg.sender] += amount;
+ totalSupply += amount;
+ emit Transfer(address(0), msg.sender, amount);
+ }
+
+ function burn(uint amount) external {
+ balanceOf[msg.sender] -= amount;
+ totalSupply -= amount;
+ emit Transfer(msg.sender, address(0), amount);
+ }
+}
+```
+
### Crie seu próprio token ERC20
Usando [Open Zeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts) é muito fácil criar seu próprio token ERC20.
@@ -44,7 +99,7 @@ Eis aqui um exemplo
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.0.0/contracts/token/ERC20/ERC20.sol";
@@ -52,7 +107,7 @@ contract MyToken is ERC20 {
constructor(string memory name, string memory symbol) ERC20(name, symbol) {
// Mint 100 tokens para msg.sender
// Semelhante a como
- // 1 dollar = 100 cents
+ // 1 real = 100 centavos
// 1 token = 1 * (10 ** decimals)
_mint(msg.sender, 100 * 10**uint(decimals()));
}
@@ -61,24 +116,26 @@ contract MyToken is ERC20 {
### Contrato para trocar tokens
-Eis um exemplo de contrato, `TokenSwap`, para negociar token ERC20 por outro.
+Aqui está um exemplo de contrato, `TokenSwap`, para trocar um token ERC20 por outro.
Este contrato negociará tokens chamando
-transferFrom(address sender, address recipient, uint256 amount)
+```solidity
+transferFrom(address remetente, address destinatario, uint256 quantidade)
+```
-que irá transferir uma quantidade de token do remetente para o destinatário.
+que irá transferir uma `quantidade` de token do `remetente` para o `destinatario`.
-Para `transferFrom` suceder, o remetente deve
+Para `transferFrom` ter sucesso, o remetente deve
-* ter mais que o `amount` de tokens no seu saldo
-* permitir `TokenSwap` para retirar o`amount` de tokens chamando `approve`
+- A `quantidade` de tokens no seu saldo deve ser maior do que está enviando
+- permitir `TokenSwap` para retirar uma `quantidade` de tokens chamando `approve`
-antes do `TokenSwap`chamar `transferFrom`
+antes do `TokenSwap` chamar `transferFrom`
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.0.0/contracts/token/ERC20/IERC20.sol";
@@ -145,3 +202,10 @@ contract TokenSwap {
}
}
```
+
+## Teste no Remix
+
+- [IERC20.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuWmVwcGVsaW4vb3BlbnplcHBlbGluLWNvbnRyYWN0cy9ibG9iL3YzLjAuMC9jb250cmFjdHMvdG9rZW4vRVJDMjAvSUVSQzIwLnNvbAppbnRlcmZhY2UgSUVSQzIwIHsKICAgIGZ1bmN0aW9uIHRvdGFsU3VwcGx5KCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zICh1aW50KTsKCiAgICBmdW5jdGlvbiBiYWxhbmNlT2YoYWRkcmVzcyBhY2NvdW50KSBleHRlcm5hbCB2aWV3IHJldHVybnMgKHVpbnQpOwoKICAgIGZ1bmN0aW9uIHRyYW5zZmVyKGFkZHJlc3MgcmVjaXBpZW50LCB1aW50IGFtb3VudCkgZXh0ZXJuYWwgcmV0dXJucyAoYm9vbCk7CgogICAgZnVuY3Rpb24gYWxsb3dhbmNlKGFkZHJlc3Mgb3duZXIsIGFkZHJlc3Mgc3BlbmRlcikgZXh0ZXJuYWwgdmlldyByZXR1cm5zICh1aW50KTsKCiAgICBmdW5jdGlvbiBhcHByb3ZlKGFkZHJlc3Mgc3BlbmRlciwgdWludCBhbW91bnQpIGV4dGVybmFsIHJldHVybnMgKGJvb2wpOwoKICAgIGZ1bmN0aW9uIHRyYW5zZmVyRnJvbSgKICAgICAgICBhZGRyZXNzIHJlbWV0ZW50ZSwKICAgICAgICBhZGRyZXNzIGRlc3RpbmF0YXJpbywKICAgICAgICB1aW50IHF1YW50aWRhZGUKICAgICkgZXh0ZXJuYWwgcmV0dXJucyAoYm9vbCk7CgogICAgZXZlbnQgVHJhbnNmZXIoYWRkcmVzcyBpbmRleGVkIGZyb20sIGFkZHJlc3MgaW5kZXhlZCB0bywgdWludCB2YWx1ZSk7CiAgICBldmVudCBBcHByb3ZhbChhZGRyZXNzIGluZGV4ZWQgb3duZXIsIGFkZHJlc3MgaW5kZXhlZCBzcGVuZGVyLCB1aW50IHZhbHVlKTsKfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
+- [ERC20.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCAiLi9JRVJDMjAuc29sIjsKCmNvbnRyYWN0IEVSQzIwIGlzIElFUkMyMCB7CiAgICB1aW50IHB1YmxpYyB0b3RhbFN1cHBseTsKICAgIG1hcHBpbmcoYWRkcmVzcyA9PiB1aW50KSBwdWJsaWMgYmFsYW5jZU9mOwogICAgbWFwcGluZyhhZGRyZXNzID0+IG1hcHBpbmcoYWRkcmVzcyA9PiB1aW50KSkgcHVibGljIGFsbG93YW5jZTsKICAgIHN0cmluZyBwdWJsaWMgbmFtZSA9ICJTb2xpZGl0eSBieSBFeGFtcGxlIjsKICAgIHN0cmluZyBwdWJsaWMgc3ltYm9sID0gIlNPTEJZRVgiOwogICAgdWludDggcHVibGljIGRlY2ltYWxzID0gMTg7CgogICAgZnVuY3Rpb24gdHJhbnNmZXIoYWRkcmVzcyByZWNpcGllbnQsIHVpbnQgYW1vdW50KSBleHRlcm5hbCByZXR1cm5zIChib29sKSB7CiAgICAgICAgYmFsYW5jZU9mW21zZy5zZW5kZXJdIC09IGFtb3VudDsKICAgICAgICBiYWxhbmNlT2ZbcmVjaXBpZW50XSArPSBhbW91bnQ7CiAgICAgICAgZW1pdCBUcmFuc2Zlcihtc2cuc2VuZGVyLCByZWNpcGllbnQsIGFtb3VudCk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgZnVuY3Rpb24gYXBwcm92ZShhZGRyZXNzIHNwZW5kZXIsIHVpbnQgYW1vdW50KSBleHRlcm5hbCByZXR1cm5zIChib29sKSB7CiAgICAgICAgYWxsb3dhbmNlW21zZy5zZW5kZXJdW3NwZW5kZXJdID0gYW1vdW50OwogICAgICAgIGVtaXQgQXBwcm92YWwobXNnLnNlbmRlciwgc3BlbmRlciwgYW1vdW50KTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBmdW5jdGlvbiB0cmFuc2ZlckZyb20oCiAgICAgICAgYWRkcmVzcyByZW1ldGVudGUsCiAgICAgICAgYWRkcmVzcyBkZXN0aW5hdGFyaW8sCiAgICAgICAgdWludCBxdWFudGlkYWRlCiAgICApIGV4dGVybmFsIHJldHVybnMgKGJvb2wpIHsKICAgICAgICBhbGxvd2FuY2Vbc2VuZGVyXVttc2cuc2VuZGVyXSAtPSBhbW91bnQ7CiAgICAgICAgYmFsYW5jZU9mW3NlbmRlcl0gLT0gYW1vdW50OwogICAgICAgIGJhbGFuY2VPZltyZWNpcGllbnRdICs9IGFtb3VudDsKICAgICAgICBlbWl0IFRyYW5zZmVyKHNlbmRlciwgcmVjaXBpZW50LCBhbW91bnQpOwogICAgICAgIHJldHVybiB0cnVlOwogICAgfQoKICAgIGZ1bmN0aW9uIG1pbnQodWludCBhbW91bnQpIGV4dGVybmFsIHsKICAgICAgICBiYWxhbmNlT2ZbbXNnLnNlbmRlcl0gKz0gYW1vdW50OwogICAgICAgIHRvdGFsU3VwcGx5ICs9IGFtb3VudDsKICAgICAgICBlbWl0IFRyYW5zZmVyKGFkZHJlc3MoMCksIG1zZy5zZW5kZXIsIGFtb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gYnVybih1aW50IGFtb3VudCkgZXh0ZXJuYWwgewogICAgICAgIGJhbGFuY2VPZlttc2cuc2VuZGVyXSAtPSBhbW91bnQ7CiAgICAgICAgdG90YWxTdXBwbHkgLT0gYW1vdW50OwogICAgICAgIGVtaXQgVHJhbnNmZXIobXNnLnNlbmRlciwgYWRkcmVzcygwKSwgYW1vdW50KTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
+- [MyToken.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCAiaHR0cHM6Ly9naXRodWIuY29tL09wZW5aZXBwZWxpbi9vcGVuemVwcGVsaW4tY29udHJhY3RzL2Jsb2IvdjQuMC4wL2NvbnRyYWN0cy90b2tlbi9FUkMyMC9FUkMyMC5zb2wiOwoKY29udHJhY3QgTXlUb2tlbiBpcyBFUkMyMCB7CiAgICBjb25zdHJ1Y3RvcihzdHJpbmcgbWVtb3J5IG5hbWUsIHN0cmluZyBtZW1vcnkgc3ltYm9sKSBFUkMyMChuYW1lLCBzeW1ib2wpIHsKICAgICAgICAvLyBNaW50IDEwMCB0b2tlbnMgcGFyYSBtc2cuc2VuZGVyCiAgICAgICAgLy8gU2VtZWxoYW50ZSBhIGNvbW8KICAgICAgICAvLyAxIHJlYWwgPSAxMDAgY2VudGF2b3MKICAgICAgICAvLyAxIHRva2VuID0gMSAqICgxMCAqKiBkZWNpbWFscykKICAgICAgICBfbWludChtc2cuc2VuZGVyLCAxMDAgKiAxMCoqdWludChkZWNpbWFscygpKSk7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
+- [TokenSwap.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmltcG9ydCAiaHR0cHM6Ly9naXRodWIuY29tL09wZW5aZXBwZWxpbi9vcGVuemVwcGVsaW4tY29udHJhY3RzL2Jsb2IvdjQuMC4wL2NvbnRyYWN0cy90b2tlbi9FUkMyMC9JRVJDMjAuc29sIjsKCi8qCkNvbW8gdHJvY2FyIHRva2VucwoKMS4gQWxpY2UgdGVtIDEwMCB0b2tlbnMgZGUgQWxpY2VDb2luLCBxdWUgZSB1bSB0b2tlbiBFUkMyMC4KMi4gQm9iIHRlbSAxMDAgdG9rZW5zIGRlIEJvYkNvaW4sIHF1ZSB0YW1iZW0gZSB1bSB0b2tlbiBFUkMyMC4KMy4gQWxpY2UgZSBCb2IgcXVlcmVtIG5lZ29jaWFyIDEwIEFsaWNlQ29pbiBwb3IgMjAgQm9iQ29pbi4KNC4gQWxpY2Ugb3UgQm9iIGltcGxhbnRhbSBUb2tlblN3YXAKNS4gQWxpY2UgYXByb3ZhIFRva2VuU3dhcCBwYXJhIHJldGlyYXIgMTAgdG9rZW5zIGRlIEFsaWNlQ29pbgo2LiBCb2IgYXByb3ZhIFRva2VuU3dhcCBwYXJhIHJldGlyYXIgMjAgdG9rZW5zIGRlIEJvYkNvaW4KNy4gQWxpY2Ugb3UgQm9iIGNoYW1hbSBUb2tlblN3YXAuc3dhcCgpCjguIEFsaWNlIGUgQm9iIG5lZ29jaWFyYW0gdG9rZW5zIGNvbSBzdWNlc3NvLgoqLwoKY29udHJhY3QgVG9rZW5Td2FwIHsKICAgIElFUkMyMCBwdWJsaWMgdG9rZW4xOwogICAgYWRkcmVzcyBwdWJsaWMgb3duZXIxOwogICAgdWludCBwdWJsaWMgYW1vdW50MTsKICAgIElFUkMyMCBwdWJsaWMgdG9rZW4yOwogICAgYWRkcmVzcyBwdWJsaWMgb3duZXIyOwogICAgdWludCBwdWJsaWMgYW1vdW50MjsKCiAgICBjb25zdHJ1Y3RvcigKICAgICAgICBhZGRyZXNzIF90b2tlbjEsCiAgICAgICAgYWRkcmVzcyBfb3duZXIxLAogICAgICAgIHVpbnQgX2Ftb3VudDEsCiAgICAgICAgYWRkcmVzcyBfdG9rZW4yLAogICAgICAgIGFkZHJlc3MgX293bmVyMiwKICAgICAgICB1aW50IF9hbW91bnQyCiAgICApIHsKICAgICAgICB0b2tlbjEgPSBJRVJDMjAoX3Rva2VuMSk7CiAgICAgICAgb3duZXIxID0gX293bmVyMTsKICAgICAgICBhbW91bnQxID0gX2Ftb3VudDE7CiAgICAgICAgdG9rZW4yID0gSUVSQzIwKF90b2tlbjIpOwogICAgICAgIG93bmVyMiA9IF9vd25lcjI7CiAgICAgICAgYW1vdW50MiA9IF9hbW91bnQyOwogICAgfQoKICAgIGZ1bmN0aW9uIHN3YXAoKSBwdWJsaWMgewogICAgICAgIHJlcXVpcmUobXNnLnNlbmRlciA9PSBvd25lcjEgfHwgbXNnLnNlbmRlciA9PSBvd25lcjIsICJOb3QgYXV0aG9yaXplZCIpOwogICAgICAgIHJlcXVpcmUoCiAgICAgICAgICAgIHRva2VuMS5hbGxvd2FuY2Uob3duZXIxLCBhZGRyZXNzKHRoaXMpKSA+PSBhbW91bnQxLAogICAgICAgICAgICAiVG9rZW4gMSBhbGxvd2FuY2UgdG9vIGxvdyIKICAgICAgICApOwogICAgICAgIHJlcXVpcmUoCiAgICAgICAgICAgIHRva2VuMi5hbGxvd2FuY2Uob3duZXIyLCBhZGRyZXNzKHRoaXMpKSA+PSBhbW91bnQyLAogICAgICAgICAgICAiVG9rZW4gMiBhbGxvd2FuY2UgdG9vIGxvdyIKICAgICAgICApOwoKICAgICAgICBfc2FmZVRyYW5zZmVyRnJvbSh0b2tlbjEsIG93bmVyMSwgb3duZXIyLCBhbW91bnQxKTsKICAgICAgICBfc2FmZVRyYW5zZmVyRnJvbSh0b2tlbjIsIG93bmVyMiwgb3duZXIxLCBhbW91bnQyKTsKICAgIH0KCiAgICBmdW5jdGlvbiBfc2FmZVRyYW5zZmVyRnJvbSgKICAgICAgICBJRVJDMjAgdG9rZW4sCiAgICAgICAgYWRkcmVzcyBzZW5kZXIsCiAgICAgICAgYWRkcmVzcyByZWNpcGllbnQsCiAgICAgICAgdWludCBhbW91bnQKICAgICkgcHJpdmF0ZSB7CiAgICAgICAgYm9vbCBzZW50ID0gdG9rZW4udHJhbnNmZXJGcm9tKHNlbmRlciwgcmVjaXBpZW50LCBhbW91bnQpOwogICAgICAgIHJlcXVpcmUoc2VudCwgIlRva2VuIHRyYW5zZmVyIGZhaWxlZCIpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/erc721.md b/src/exemplos/aplicacoes/erc721.md
new file mode 100644
index 0000000..2009792
--- /dev/null
+++ b/src/exemplos/aplicacoes/erc721.md
@@ -0,0 +1,214 @@
+# ERC721
+
+Exemplo de um contrato ERC721.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+interface IERC165 {
+ function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+interface IERC721 is IERC165 {
+ function balanceOf(address owner) external view returns (uint balance);
+
+ function ownerOf(uint tokenId) external view returns (address owner);
+
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint tokenId
+ ) external;
+
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint tokenId,
+ bytes calldata data
+ ) external;
+
+ function transferFrom(
+ address from,
+ address to,
+ uint tokenId
+ ) external;
+
+ function approve(address to, uint tokenId) external;
+
+ function getApproved(uint tokenId) external view returns (address operator);
+
+ function setApprovalForAll(address operator, bool _approved) external;
+
+ function isApprovedForAll(address owner, address operator)
+ external
+ view
+ returns (bool);
+}
+
+interface IERC721Receiver {
+ function onERC721Received(
+ address operator,
+ address from,
+ uint tokenId,
+ bytes calldata data
+ ) external returns (bytes4);
+}
+
+contract ERC721 is IERC721 {
+ event Transfer(address indexed from, address indexed to, uint indexed id);
+ event Approval(address indexed owner, address indexed spender, uint indexed id);
+ event ApprovalForAll(
+ address indexed owner,
+ address indexed operator,
+ bool approved
+ );
+
+ // Mapping de token ID para endereço do dono
+ mapping(uint => address) internal _ownerOf;
+
+ // Mapping do endereço do dono para contagem de tokens
+ mapping(address => uint) internal _balanceOf;
+
+ // Mapping de token ID para endereços aprovados
+ mapping(uint => address) internal _approvals;
+
+ // Mapping do dono para operatores aprovados
+ mapping(address => mapping(address => bool)) public isApprovedForAll;
+
+ function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
+ return
+ interfaceId == type(IERC721).interfaceId ||
+ interfaceId == type(IERC165).interfaceId;
+ }
+
+ function ownerOf(uint id) external view returns (address owner) {
+ owner = _ownerOf[id];
+ require(owner != address(0), "token doesn't exist");
+ }
+
+ function balanceOf(address owner) external view returns (uint) {
+ require(owner != address(0), "owner = zero address");
+ return _balanceOf[owner];
+ }
+
+ function setApprovalForAll(address operator, bool approved) external {
+ isApprovedForAll[msg.sender][operator] = approved;
+ emit ApprovalForAll(msg.sender, operator, approved);
+ }
+
+ function approve(address spender, uint id) external {
+ address owner = _ownerOf[id];
+ require(
+ msg.sender == owner || isApprovedForAll[owner][msg.sender],
+ "not authorized"
+ );
+
+ _approvals[id] = spender;
+
+ emit Approval(owner, spender, id);
+ }
+
+ function getApproved(uint id) external view returns (address) {
+ require(_ownerOf[id] != address(0), "token doesn't exist");
+ return _approvals[id];
+ }
+
+ function _isApprovedOrOwner(
+ address owner,
+ address spender,
+ uint id
+ ) internal view returns (bool) {
+ return (spender == owner ||
+ isApprovedForAll[owner][spender] ||
+ spender == _approvals[id]);
+ }
+
+ function transferFrom(
+ address from,
+ address to,
+ uint id
+ ) public {
+ require(from == _ownerOf[id], "from != owner");
+ require(to != address(0), "transfer to zero address");
+
+ require(_isApprovedOrOwner(from, msg.sender, id), "not authorized");
+
+ _balanceOf[from]--;
+ _balanceOf[to]++;
+ _ownerOf[id] = to;
+
+ delete _approvals[id];
+
+ emit Transfer(from, to, id);
+ }
+
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint id
+ ) external {
+ transferFrom(from, to, id);
+
+ require(
+ to.code.length == 0 ||
+ IERC721Receiver(to).onERC721Received(msg.sender, from, id, "") ==
+ IERC721Receiver.onERC721Received.selector,
+ "unsafe recipient"
+ );
+ }
+
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint id,
+ bytes calldata data
+ ) external {
+ transferFrom(from, to, id);
+
+ require(
+ to.code.length == 0 ||
+ IERC721Receiver(to).onERC721Received(msg.sender, from, id, data) ==
+ IERC721Receiver.onERC721Received.selector,
+ "unsafe recipient"
+ );
+ }
+
+ function _mint(address to, uint id) internal {
+ require(to != address(0), "mint to zero address");
+ require(_ownerOf[id] == address(0), "already minted");
+
+ _balanceOf[to]++;
+ _ownerOf[id] = to;
+
+ emit Transfer(address(0), to, id);
+ }
+
+ function _burn(uint id) internal {
+ address owner = _ownerOf[id];
+ require(owner != address(0), "not minted");
+
+ _balanceOf[owner] -= 1;
+
+ delete _ownerOf[id];
+ delete _approvals[id];
+
+ emit Transfer(owner, address(0), id);
+ }
+}
+
+contract MyNFT is ERC721 {
+ function mint(address to, uint id) external {
+ _mint(to, id);
+ }
+
+ function burn(uint id) external {
+ require(msg.sender == _ownerOf[id], "not owner");
+ _burn(id);
+ }
+}
+```
+
+## Teste no Remix
+
+- [ERC721.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmludGVyZmFjZSBJRVJDMTY1IHsKICAgIGZ1bmN0aW9uIHN1cHBvcnRzSW50ZXJmYWNlKGJ5dGVzNCBpbnRlcmZhY2VJRCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChib29sKTsKfQoKaW50ZXJmYWNlIElFUkM3MjEgaXMgSUVSQzE2NSB7CiAgICBmdW5jdGlvbiBiYWxhbmNlT2YoYWRkcmVzcyBvd25lcikgZXh0ZXJuYWwgdmlldyByZXR1cm5zICh1aW50IGJhbGFuY2UpOwoKICAgIGZ1bmN0aW9uIG93bmVyT2YodWludCB0b2tlbklkKSBleHRlcm5hbCB2aWV3IHJldHVybnMgKGFkZHJlc3Mgb3duZXIpOwoKICAgIGZ1bmN0aW9uIHNhZmVUcmFuc2ZlckZyb20oCiAgICAgICAgYWRkcmVzcyBmcm9tLAogICAgICAgIGFkZHJlc3MgdG8sCiAgICAgICAgdWludCB0b2tlbklkCiAgICApIGV4dGVybmFsOwoKICAgIGZ1bmN0aW9uIHNhZmVUcmFuc2ZlckZyb20oCiAgICAgICAgYWRkcmVzcyBmcm9tLAogICAgICAgIGFkZHJlc3MgdG8sCiAgICAgICAgdWludCB0b2tlbklkLAogICAgICAgIGJ5dGVzIGNhbGxkYXRhIGRhdGEKICAgICkgZXh0ZXJuYWw7CgogICAgZnVuY3Rpb24gdHJhbnNmZXJGcm9tKAogICAgICAgIGFkZHJlc3MgZnJvbSwKICAgICAgICBhZGRyZXNzIHRvLAogICAgICAgIHVpbnQgdG9rZW5JZAogICAgKSBleHRlcm5hbDsKCiAgICBmdW5jdGlvbiBhcHByb3ZlKGFkZHJlc3MgdG8sIHVpbnQgdG9rZW5JZCkgZXh0ZXJuYWw7CgogICAgZnVuY3Rpb24gZ2V0QXBwcm92ZWQodWludCB0b2tlbklkKSBleHRlcm5hbCB2aWV3IHJldHVybnMgKGFkZHJlc3Mgb3BlcmF0b3IpOwoKICAgIGZ1bmN0aW9uIHNldEFwcHJvdmFsRm9yQWxsKGFkZHJlc3Mgb3BlcmF0b3IsIGJvb2wgX2FwcHJvdmVkKSBleHRlcm5hbDsKCiAgICBmdW5jdGlvbiBpc0FwcHJvdmVkRm9yQWxsKGFkZHJlc3Mgb3duZXIsIGFkZHJlc3Mgb3BlcmF0b3IpCiAgICAgICAgZXh0ZXJuYWwKICAgICAgICB2aWV3CiAgICAgICAgcmV0dXJucyAoYm9vbCk7Cn0KCmludGVyZmFjZSBJRVJDNzIxUmVjZWl2ZXIgewogICAgZnVuY3Rpb24gb25FUkM3MjFSZWNlaXZlZCgKICAgICAgICBhZGRyZXNzIG9wZXJhdG9yLAogICAgICAgIGFkZHJlc3MgZnJvbSwKICAgICAgICB1aW50IHRva2VuSWQsCiAgICAgICAgYnl0ZXMgY2FsbGRhdGEgZGF0YQogICAgKSBleHRlcm5hbCByZXR1cm5zIChieXRlczQpOwp9Cgpjb250cmFjdCBFUkM3MjEgaXMgSUVSQzcyMSB7CiAgICBldmVudCBUcmFuc2ZlcihhZGRyZXNzIGluZGV4ZWQgZnJvbSwgYWRkcmVzcyBpbmRleGVkIHRvLCB1aW50IGluZGV4ZWQgaWQpOwogICAgZXZlbnQgQXBwcm92YWwoYWRkcmVzcyBpbmRleGVkIG93bmVyLCBhZGRyZXNzIGluZGV4ZWQgc3BlbmRlciwgdWludCBpbmRleGVkIGlkKTsKICAgIGV2ZW50IEFwcHJvdmFsRm9yQWxsKAogICAgICAgIGFkZHJlc3MgaW5kZXhlZCBvd25lciwKICAgICAgICBhZGRyZXNzIGluZGV4ZWQgb3BlcmF0b3IsCiAgICAgICAgYm9vbCBhcHByb3ZlZAogICAgKTsKCiAgICAvLyBNYXBwaW5nIGRlIHRva2VuIElEIHBhcmEgZW5kZXJlY28gZG8gZG9ubwogICAgbWFwcGluZyh1aW50ID0+IGFkZHJlc3MpIGludGVybmFsIF9vd25lck9mOwoKICAgIC8vIE1hcHBpbmcgZG8gZW5kZXJlY28gZG8gZG9ubyBwYXJhIGNvbnRhZ2VtIGRlIHRva2VucwogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQpIGludGVybmFsIF9iYWxhbmNlT2Y7CgogICAgLy8gTWFwcGluZyBkZSB0b2tlbiBJRCBwYXJhIGVuZGVyZWNvcyBhcHJvdmFkb3MKICAgIG1hcHBpbmcodWludCA9PiBhZGRyZXNzKSBpbnRlcm5hbCBfYXBwcm92YWxzOwoKICAgIC8vIE1hcHBpbmcgZG8gZG9ubyBwYXJhIG9wZXJhdG9yZXMgYXByb3ZhZG9zCiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gbWFwcGluZyhhZGRyZXNzID0+IGJvb2wpKSBwdWJsaWMgaXNBcHByb3ZlZEZvckFsbDsKCiAgICBmdW5jdGlvbiBzdXBwb3J0c0ludGVyZmFjZShieXRlczQgaW50ZXJmYWNlSWQpIGV4dGVybmFsIHB1cmUgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybgogICAgICAgICAgICBpbnRlcmZhY2VJZCA9PSB0eXBlKElFUkM3MjEpLmludGVyZmFjZUlkIHx8CiAgICAgICAgICAgIGludGVyZmFjZUlkID09IHR5cGUoSUVSQzE2NSkuaW50ZXJmYWNlSWQ7CiAgICB9CgogICAgZnVuY3Rpb24gb3duZXJPZih1aW50IGlkKSBleHRlcm5hbCB2aWV3IHJldHVybnMgKGFkZHJlc3Mgb3duZXIpIHsKICAgICAgICBvd25lciA9IF9vd25lck9mW2lkXTsKICAgICAgICByZXF1aXJlKG93bmVyICE9IGFkZHJlc3MoMCksICJ0b2tlbiBkb2Vzbid0IGV4aXN0Iik7CiAgICB9CgogICAgZnVuY3Rpb24gYmFsYW5jZU9mKGFkZHJlc3Mgb3duZXIpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAodWludCkgewogICAgICAgIHJlcXVpcmUob3duZXIgIT0gYWRkcmVzcygwKSwgIm93bmVyID0gemVybyBhZGRyZXNzIik7CiAgICAgICAgcmV0dXJuIF9iYWxhbmNlT2Zbb3duZXJdOwogICAgfQoKICAgIGZ1bmN0aW9uIHNldEFwcHJvdmFsRm9yQWxsKGFkZHJlc3Mgb3BlcmF0b3IsIGJvb2wgYXBwcm92ZWQpIGV4dGVybmFsIHsKICAgICAgICBpc0FwcHJvdmVkRm9yQWxsW21zZy5zZW5kZXJdW29wZXJhdG9yXSA9IGFwcHJvdmVkOwogICAgICAgIGVtaXQgQXBwcm92YWxGb3JBbGwobXNnLnNlbmRlciwgb3BlcmF0b3IsIGFwcHJvdmVkKTsKICAgIH0KCiAgICBmdW5jdGlvbiBhcHByb3ZlKGFkZHJlc3Mgc3BlbmRlciwgdWludCBpZCkgZXh0ZXJuYWwgewogICAgICAgIGFkZHJlc3Mgb3duZXIgPSBfb3duZXJPZltpZF07CiAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgbXNnLnNlbmRlciA9PSBvd25lciB8fCBpc0FwcHJvdmVkRm9yQWxsW293bmVyXVttc2cuc2VuZGVyXSwKICAgICAgICAgICAgIm5vdCBhdXRob3JpemVkIgogICAgICAgICk7CgogICAgICAgIF9hcHByb3ZhbHNbaWRdID0gc3BlbmRlcjsKCiAgICAgICAgZW1pdCBBcHByb3ZhbChvd25lciwgc3BlbmRlciwgaWQpOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldEFwcHJvdmVkKHVpbnQgaWQpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoYWRkcmVzcykgewogICAgICAgIHJlcXVpcmUoX293bmVyT2ZbaWRdICE9IGFkZHJlc3MoMCksICJ0b2tlbiBkb2Vzbid0IGV4aXN0Iik7CiAgICAgICAgcmV0dXJuIF9hcHByb3ZhbHNbaWRdOwogICAgfQoKICAgIGZ1bmN0aW9uIF9pc0FwcHJvdmVkT3JPd25lcigKICAgICAgICBhZGRyZXNzIG93bmVyLAogICAgICAgIGFkZHJlc3Mgc3BlbmRlciwKICAgICAgICB1aW50IGlkCiAgICApIGludGVybmFsIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybiAoc3BlbmRlciA9PSBvd25lciB8fAogICAgICAgICAgICBpc0FwcHJvdmVkRm9yQWxsW293bmVyXVtzcGVuZGVyXSB8fAogICAgICAgICAgICBzcGVuZGVyID09IF9hcHByb3ZhbHNbaWRdKTsKICAgIH0KCiAgICBmdW5jdGlvbiB0cmFuc2ZlckZyb20oCiAgICAgICAgYWRkcmVzcyBmcm9tLAogICAgICAgIGFkZHJlc3MgdG8sCiAgICAgICAgdWludCBpZAogICAgKSBwdWJsaWMgewogICAgICAgIHJlcXVpcmUoZnJvbSA9PSBfb3duZXJPZltpZF0sICJmcm9tICE9IG93bmVyIik7CiAgICAgICAgcmVxdWlyZSh0byAhPSBhZGRyZXNzKDApLCAidHJhbnNmZXIgdG8gemVybyBhZGRyZXNzIik7CgogICAgICAgIHJlcXVpcmUoX2lzQXBwcm92ZWRPck93bmVyKGZyb20sIG1zZy5zZW5kZXIsIGlkKSwgIm5vdCBhdXRob3JpemVkIik7CgogICAgICAgIF9iYWxhbmNlT2ZbZnJvbV0tLTsKICAgICAgICBfYmFsYW5jZU9mW3RvXSsrOwogICAgICAgIF9vd25lck9mW2lkXSA9IHRvOwoKICAgICAgICBkZWxldGUgX2FwcHJvdmFsc1tpZF07CgogICAgICAgIGVtaXQgVHJhbnNmZXIoZnJvbSwgdG8sIGlkKTsKICAgIH0KCiAgICBmdW5jdGlvbiBzYWZlVHJhbnNmZXJGcm9tKAogICAgICAgIGFkZHJlc3MgZnJvbSwKICAgICAgICBhZGRyZXNzIHRvLAogICAgICAgIHVpbnQgaWQKICAgICkgZXh0ZXJuYWwgewogICAgICAgIHRyYW5zZmVyRnJvbShmcm9tLCB0bywgaWQpOwoKICAgICAgICByZXF1aXJlKAogICAgICAgICAgICB0by5jb2RlLmxlbmd0aCA9PSAwIHx8CiAgICAgICAgICAgICAgICBJRVJDNzIxUmVjZWl2ZXIodG8pLm9uRVJDNzIxUmVjZWl2ZWQobXNnLnNlbmRlciwgZnJvbSwgaWQsICIiKSA9PQogICAgICAgICAgICAgICAgSUVSQzcyMVJlY2VpdmVyLm9uRVJDNzIxUmVjZWl2ZWQuc2VsZWN0b3IsCiAgICAgICAgICAgICJ1bnNhZmUgcmVjaXBpZW50IgogICAgICAgICk7CiAgICB9CgogICAgZnVuY3Rpb24gc2FmZVRyYW5zZmVyRnJvbSgKICAgICAgICBhZGRyZXNzIGZyb20sCiAgICAgICAgYWRkcmVzcyB0bywKICAgICAgICB1aW50IGlkLAogICAgICAgIGJ5dGVzIGNhbGxkYXRhIGRhdGEKICAgICkgZXh0ZXJuYWwgewogICAgICAgIHRyYW5zZmVyRnJvbShmcm9tLCB0bywgaWQpOwoKICAgICAgICByZXF1aXJlKAogICAgICAgICAgICB0by5jb2RlLmxlbmd0aCA9PSAwIHx8CiAgICAgICAgICAgICAgICBJRVJDNzIxUmVjZWl2ZXIodG8pLm9uRVJDNzIxUmVjZWl2ZWQobXNnLnNlbmRlciwgZnJvbSwgaWQsIGRhdGEpID09CiAgICAgICAgICAgICAgICBJRVJDNzIxUmVjZWl2ZXIub25FUkM3MjFSZWNlaXZlZC5zZWxlY3RvciwKICAgICAgICAgICAgInVuc2FmZSByZWNpcGllbnQiCiAgICAgICAgKTsKICAgIH0KCiAgICBmdW5jdGlvbiBfbWludChhZGRyZXNzIHRvLCB1aW50IGlkKSBpbnRlcm5hbCB7CiAgICAgICAgcmVxdWlyZSh0byAhPSBhZGRyZXNzKDApLCAibWludCB0byB6ZXJvIGFkZHJlc3MiKTsKICAgICAgICByZXF1aXJlKF9vd25lck9mW2lkXSA9PSBhZGRyZXNzKDApLCAiYWxyZWFkeSBtaW50ZWQiKTsKCiAgICAgICAgX2JhbGFuY2VPZlt0b10rKzsKICAgICAgICBfb3duZXJPZltpZF0gPSB0bzsKCiAgICAgICAgZW1pdCBUcmFuc2ZlcihhZGRyZXNzKDApLCB0bywgaWQpOwogICAgfQoKICAgIGZ1bmN0aW9uIF9idXJuKHVpbnQgaWQpIGludGVybmFsIHsKICAgICAgICBhZGRyZXNzIG93bmVyID0gX293bmVyT2ZbaWRdOwogICAgICAgIHJlcXVpcmUob3duZXIgIT0gYWRkcmVzcygwKSwgIm5vdCBtaW50ZWQiKTsKCiAgICAgICAgX2JhbGFuY2VPZltvd25lcl0gLT0gMTsKCiAgICAgICAgZGVsZXRlIF9vd25lck9mW2lkXTsKICAgICAgICBkZWxldGUgX2FwcHJvdmFsc1tpZF07CgogICAgICAgIGVtaXQgVHJhbnNmZXIob3duZXIsIGFkZHJlc3MoMCksIGlkKTsKICAgIH0KfQoKY29udHJhY3QgTXlORlQgaXMgRVJDNzIxIHsKICAgIGZ1bmN0aW9uIG1pbnQoYWRkcmVzcyB0bywgdWludCBpZCkgZXh0ZXJuYWwgewogICAgICAgIF9taW50KHRvLCBpZCk7CiAgICB9CgogICAgZnVuY3Rpb24gYnVybih1aW50IGlkKSBleHRlcm5hbCB7CiAgICAgICAgcmVxdWlyZShtc2cuc2VuZGVyID09IF9vd25lck9mW2lkXSwgIm5vdCBvd25lciIpOwogICAgICAgIF9idXJuKGlkKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/exponenciacao-binaria-em-assembly.md b/src/exemplos/aplicacoes/exponenciacao-binaria-em-assembly.md
new file mode 100644
index 0000000..30a3a2a
--- /dev/null
+++ b/src/exemplos/aplicacoes/exponenciacao-binaria-em-assembly.md
@@ -0,0 +1,66 @@
+# Exponenciação binária em assembly
+
+Exemplo de exponenciação binária em assembly
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+contract AssemblyBinExp {
+ // Binary exponentiation to calculate x**n
+ function rpow(uint256 x, uint256 n, uint256 b)
+ public
+ pure
+ returns (uint256 z)
+ {
+ assembly {
+ switch x
+ // x = 0
+ case 0 {
+ switch n
+ // n = 0 --> x**n = 0**0 --> 1
+ case 0 { z := b }
+ // n > 0 --> x**n = 0**n --> 0
+ default { z := 0 }
+ }
+ default {
+ switch mod(n, 2)
+ // x > 0 and n is even --> z = 1
+ case 0 { z := b }
+ // x > 0 and n is odd --> z = x
+ default { z := x }
+
+ let half := div(b, 2) // for rounding.
+ // n = n / 2, while n > 0, n = n / 2
+ for { n := div(n, 2) } n { n := div(n, 2) } {
+ let xx := mul(x, x)
+ // Check overflow - revert if xx / x != x
+ if iszero(eq(div(xx, x), x)) { revert(0, 0) }
+ // Round (xx + half) / b
+ let xxRound := add(xx, half)
+ // Check overflow - revert if xxRound < xx
+ if lt(xxRound, xx) { revert(0, 0) }
+ x := div(xxRound, b)
+ // if n % 2 == 1
+ if mod(n, 2) {
+ let zx := mul(z, x)
+ // revert if x != 0 and zx / x != z
+ if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) {
+ revert(0, 0)
+ }
+ // Round (zx + half) / b
+ let zxRound := add(zx, half)
+ // Check overflow - revert if zxRound < zx
+ if lt(zxRound, zx) { revert(0, 0) }
+ z := div(zxRound, b)
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+## Teste no Remix
+
+- [EtherWallet.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IEFzc2VtYmx5QmluRXhwIHsKICAgIC8vIEJpbmFyeSBleHBvbmVudGlhdGlvbiB0byBjYWxjdWxhdGUgeCoqbgogICAgZnVuY3Rpb24gcnBvdyh1aW50MjU2IHgsIHVpbnQyNTYgbiwgdWludDI1NiBiKQogICAgICAgIHB1YmxpYwogICAgICAgIHB1cmUKICAgICAgICByZXR1cm5zICh1aW50MjU2IHopCiAgICB7CiAgICAgICAgYXNzZW1ibHkgewogICAgICAgICAgICBzd2l0Y2ggeAogICAgICAgICAgICAvLyB4ID0gMAogICAgICAgICAgICBjYXNlIDAgewogICAgICAgICAgICAgICAgc3dpdGNoIG4KICAgICAgICAgICAgICAgIC8vIG4gPSAwIC0tPiB4KipuID0gMCoqMCAtLT4gMQogICAgICAgICAgICAgICAgY2FzZSAwIHsgeiA6PSBiIH0KICAgICAgICAgICAgICAgIC8vIG4gPiAwIC0tPiB4KipuID0gMCoqbiAtLT4gMAogICAgICAgICAgICAgICAgZGVmYXVsdCB7IHogOj0gMCB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGVmYXVsdCB7CiAgICAgICAgICAgICAgICBzd2l0Y2ggbW9kKG4sIDIpCiAgICAgICAgICAgICAgICAvLyB4ID4gMCBhbmQgbiBpcyBldmVuIC0tPiB6ID0gMQogICAgICAgICAgICAgICAgY2FzZSAwIHsgeiA6PSBiIH0KICAgICAgICAgICAgICAgIC8vIHggPiAwIGFuZCBuIGlzIG9kZCAtLT4geiA9IHgKICAgICAgICAgICAgICAgIGRlZmF1bHQgeyB6IDo9IHggfQoKICAgICAgICAgICAgICAgIGxldCBoYWxmIDo9IGRpdihiLCAyKSAvLyBmb3Igcm91bmRpbmcuCiAgICAgICAgICAgICAgICAvLyBuID0gbiAvIDIsIHdoaWxlIG4gPiAwLCBuID0gbiAvIDIKICAgICAgICAgICAgICAgIGZvciB7IG4gOj0gZGl2KG4sIDIpIH0gbiB7IG4gOj0gZGl2KG4sIDIpIH0gewogICAgICAgICAgICAgICAgICAgIGxldCB4eCA6PSBtdWwoeCwgeCkKICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBvdmVyZmxvdyAtIHJldmVydCBpZiB4eCAvIHggIT0geAogICAgICAgICAgICAgICAgICAgIGlmIGlzemVybyhlcShkaXYoeHgsIHgpLCB4KSkgeyByZXZlcnQoMCwgMCkgfQogICAgICAgICAgICAgICAgICAgIC8vIFJvdW5kICh4eCArIGhhbGYpIC8gYgogICAgICAgICAgICAgICAgICAgIGxldCB4eFJvdW5kIDo9IGFkZCh4eCwgaGFsZikKICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBvdmVyZmxvdyAtIHJldmVydCBpZiB4eFJvdW5kIDwgeHgKICAgICAgICAgICAgICAgICAgICBpZiBsdCh4eFJvdW5kLCB4eCkgeyByZXZlcnQoMCwgMCkgfQogICAgICAgICAgICAgICAgICAgIHggOj0gZGl2KHh4Um91bmQsIGIpCiAgICAgICAgICAgICAgICAgICAgLy8gaWYgbiAlIDIgPT0gMQogICAgICAgICAgICAgICAgICAgIGlmIG1vZChuLCAyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGxldCB6eCA6PSBtdWwoeiwgeCkKICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmV2ZXJ0IGlmIHggIT0gMCBhbmQgenggLyB4ICE9IHoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgYW5kKGlzemVybyhpc3plcm8oeCkpLCBpc3plcm8oZXEoZGl2KHp4LCB4KSwgeikpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXZlcnQoMCwgMCkKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAvLyBSb3VuZCAoenggKyBoYWxmKSAvIGIKICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHp4Um91bmQgOj0gYWRkKHp4LCBoYWxmKQogICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBvdmVyZmxvdyAtIHJldmVydCBpZiB6eFJvdW5kIDwgengKICAgICAgICAgICAgICAgICAgICAgICAgaWYgbHQoenhSb3VuZCwgengpIHsgcmV2ZXJ0KDAsIDApIH0KICAgICAgICAgICAgICAgICAgICAgICAgeiA6PSBkaXYoenhSb3VuZCwgYikKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cn0K=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/gravar-em-qualquer-slot.md b/src/exemplos/aplicacoes/gravar-em-qualquer-slot.md
new file mode 100644
index 0000000..983499f
--- /dev/null
+++ b/src/exemplos/aplicacoes/gravar-em-qualquer-slot.md
@@ -0,0 +1,46 @@
+# Gravar em qualquer slot
+
+O armazenamento de solidity é como um array de comprimento 2256. Cada slot no array pode armazenar 32 bytes.
+
+As variáveis de estado definem quais slots serão usados para armazenar dados.
+
+No entanto, usando assembly, você pode gravar em qualquer slot.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+library StorageSlot {
+ // Envolver o endereço numa estrutura para que possa ser passado como um ponteiro de armazenamento
+ struct AddressSlot {
+ address value;
+ }
+
+ function getAddressSlot(
+ bytes32 slot
+ ) internal pure returns (AddressSlot storage pointer) {
+ assembly {
+ // Obtém o ponteiro para AddressSlot armazenado na slot
+ pointer.slot := slot
+ }
+ }
+}
+
+contract TestSlot {
+ bytes32 public constant TEST_SLOT = keccak256("TEST_SLOT");
+
+ function write(address _addr) external {
+ StorageSlot.AddressSlot storage data = StorageSlot.getAddressSlot(TEST_SLOT);
+ data.value = _addr;
+ }
+
+ function get() external view returns (address) {
+ StorageSlot.AddressSlot storage data = StorageSlot.getAddressSlot(TEST_SLOT);
+ return data.value;
+ }
+}
+```
+
+## Teste no Remix
+
+- [Slot.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmxpYnJhcnkgU3RvcmFnZVNsb3QgewogICAgLy8gRW52b2x2ZXIgbyBlbmRlcmVjbyBudW1hIGVzdHJ1dHVyYSBwYXJhIHF1ZSBwb3NzYSBzZXIgcGFzc2FkbyBjb21vIHVtIHBvbnRlaXJvIGRlIGFybWF6ZW5hbWVudG8KICAgIHN0cnVjdCBBZGRyZXNzU2xvdCB7CiAgICAgICAgYWRkcmVzcyB2YWx1ZTsKICAgIH0KCiAgICBmdW5jdGlvbiBnZXRBZGRyZXNzU2xvdCgKICAgICAgICBieXRlczMyIHNsb3QKICAgICkgaW50ZXJuYWwgcHVyZSByZXR1cm5zIChBZGRyZXNzU2xvdCBzdG9yYWdlIHBvaW50ZXIpIHsKICAgICAgICBhc3NlbWJseSB7CiAgICAgICAgICAgIC8vIE9idGVtIG8gcG9udGVpcm8gcGFyYSBBZGRyZXNzU2xvdCBhcm1hemVuYWRvIG5hIHNsb3QKICAgICAgICAgICAgcG9pbnRlci5zbG90IDo9IHNsb3QKICAgICAgICB9CiAgICB9Cn0KCmNvbnRyYWN0IFRlc3RTbG90IHsKICAgIGJ5dGVzMzIgcHVibGljIGNvbnN0YW50IFRFU1RfU0xPVCA9IGtlY2NhazI1NigiVEVTVF9TTE9UIik7CgogICAgZnVuY3Rpb24gd3JpdGUoYWRkcmVzcyBfYWRkcikgZXh0ZXJuYWwgewogICAgICAgIFN0b3JhZ2VTbG90LkFkZHJlc3NTbG90IHN0b3JhZ2UgZGF0YSA9IFN0b3JhZ2VTbG90LmdldEFkZHJlc3NTbG90KFRFU1RfU0xPVCk7CiAgICAgICAgZGF0YS52YWx1ZSA9IF9hZGRyOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldCgpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAoYWRkcmVzcykgewogICAgICAgIFN0b3JhZ2VTbG90LkFkZHJlc3NTbG90IHN0b3JhZ2UgZGF0YSA9IFN0b3JhZ2VTbG90LmdldEFkZHJlc3NTbG90KFRFU1RfU0xPVCk7CiAgICAgICAgcmV0dXJuIGRhdGEudmFsdWU7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/implante-qualquer-contrato.md b/src/exemplos/aplicacoes/implante-qualquer-contrato.md
index 3dfacbf..c6f0a50 100644
--- a/src/exemplos/aplicacoes/implante-qualquer-contrato.md
+++ b/src/exemplos/aplicacoes/implante-qualquer-contrato.md
@@ -6,12 +6,12 @@ Por este exemplo, você pode obter bytecodes do contrato chamando `Helper.getByt
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
contract Proxy {
event Deploy(address);
- fallback() external payable {}
+ receive() external payable {}
function deploy(bytes memory _code) external payable returns (address addr) {
assembly {
@@ -21,7 +21,7 @@ contract Proxy {
// n = tamanho do código
addr := create(callvalue(), add(_code, 0x20), mload(_code))
}
- // retorna endereço 0 em erro
+ // retorna address 0 on error
require(addr != address(0), "deploy failed");
emit Deploy(addr);
@@ -70,3 +70,7 @@ contract Helper {
}
}
```
+
+## Teste no Remix
+
+- [Proxy.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IFByb3h5IHsKICAgIGV2ZW50IERlcGxveShhZGRyZXNzKTsKCiAgICByZWNlaXZlKCkgZXh0ZXJuYWwgcGF5YWJsZSB7fQoKICAgIGZ1bmN0aW9uIGRlcGxveShieXRlcyBtZW1vcnkgX2NvZGUpIGV4dGVybmFsIHBheWFibGUgcmV0dXJucyAoYWRkcmVzcyBhZGRyKSB7CiAgICAgICAgYXNzZW1ibHkgewogICAgICAgICAgICAvLyBjcmVhdGUodiwgcCwgbikKICAgICAgICAgICAgLy8gdiA9IHF1YW50aWRhZGUgZGUgRVRIIGEgc2VyIGVudmlhZG8KICAgICAgICAgICAgLy8gcCA9IHBvbnRlaXJvIG5hIG1lbW9yaWEgcGFyYSBpbmljaWFyIG8gY29kaWdvCiAgICAgICAgICAgIC8vIG4gPSB0YW1hbmhvIGRvIGNvZGlnbwogICAgICAgICAgICBhZGRyIDo9IGNyZWF0ZShjYWxsdmFsdWUoKSwgYWRkKF9jb2RlLCAweDIwKSwgbWxvYWQoX2NvZGUpKQogICAgICAgIH0KICAgICAgICAvLyByZXRvcm5hIGFkZHJlc3MgMCBvbiBlcnJvcgogICAgICAgIHJlcXVpcmUoYWRkciAhPSBhZGRyZXNzKDApLCAiZGVwbG95IGZhaWxlZCIpOwoKICAgICAgICBlbWl0IERlcGxveShhZGRyKTsKICAgIH0KCiAgICBmdW5jdGlvbiBleGVjdXRlKGFkZHJlc3MgX3RhcmdldCwgYnl0ZXMgbWVtb3J5IF9kYXRhKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgICAgICAoYm9vbCBzdWNjZXNzLCApID0gX3RhcmdldC5jYWxse3ZhbHVlOiBtc2cudmFsdWV9KF9kYXRhKTsKICAgICAgICByZXF1aXJlKHN1Y2Nlc3MsICJmYWlsZWQiKTsKICAgIH0KfQoKY29udHJhY3QgVGVzdENvbnRyYWN0MSB7CiAgICBhZGRyZXNzIHB1YmxpYyBvd25lciA9IG1zZy5zZW5kZXI7CgogICAgZnVuY3Rpb24gc2V0T3duZXIoYWRkcmVzcyBfb3duZXIpIHB1YmxpYyB7CiAgICAgICAgcmVxdWlyZShtc2cuc2VuZGVyID09IG93bmVyLCAibm90IG93bmVyIik7CiAgICAgICAgb3duZXIgPSBfb3duZXI7CiAgICB9Cn0KCmNvbnRyYWN0IFRlc3RDb250cmFjdDIgewogICAgYWRkcmVzcyBwdWJsaWMgb3duZXIgPSBtc2cuc2VuZGVyOwogICAgdWludCBwdWJsaWMgdmFsdWUgPSBtc2cudmFsdWU7CiAgICB1aW50IHB1YmxpYyB4OwogICAgdWludCBwdWJsaWMgeTsKCiAgICBjb25zdHJ1Y3Rvcih1aW50IF94LCB1aW50IF95KSBwYXlhYmxlIHsKICAgICAgICB4ID0gX3g7CiAgICAgICAgeSA9IF95OwogICAgfQp9Cgpjb250cmFjdCBIZWxwZXIgewogICAgZnVuY3Rpb24gZ2V0Qnl0ZWNvZGUxKCkgZXh0ZXJuYWwgcHVyZSByZXR1cm5zIChieXRlcyBtZW1vcnkpIHsKICAgICAgICBieXRlcyBtZW1vcnkgYnl0ZWNvZGUgPSB0eXBlKFRlc3RDb250cmFjdDEpLmNyZWF0aW9uQ29kZTsKICAgICAgICByZXR1cm4gYnl0ZWNvZGU7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0Qnl0ZWNvZGUyKHVpbnQgX3gsIHVpbnQgX3kpIGV4dGVybmFsIHB1cmUgcmV0dXJucyAoYnl0ZXMgbWVtb3J5KSB7CiAgICAgICAgYnl0ZXMgbWVtb3J5IGJ5dGVjb2RlID0gdHlwZShUZXN0Q29udHJhY3QyKS5jcmVhdGlvbkNvZGU7CiAgICAgICAgcmV0dXJuIGFiaS5lbmNvZGVQYWNrZWQoYnl0ZWNvZGUsIGFiaS5lbmNvZGUoX3gsIF95KSk7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0Q2FsbGRhdGEoYWRkcmVzcyBfb3duZXIpIGV4dGVybmFsIHB1cmUgcmV0dXJucyAoYnl0ZXMgbWVtb3J5KSB7CiAgICAgICAgcmV0dXJuIGFiaS5lbmNvZGVXaXRoU2lnbmF0dXJlKCJzZXRPd25lcihhZGRyZXNzKSIsIF9vd25lcik7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/leilao-holandes.md b/src/exemplos/aplicacoes/leilao-holandes.md
index fabe03b..78f510f 100644
--- a/src/exemplos/aplicacoes/leilao-holandes.md
+++ b/src/exemplos/aplicacoes/leilao-holandes.md
@@ -7,12 +7,12 @@ Leilão holandês de NFT.
1. O vendedor de NFT implementa este contrato estabelecendo um preço inicial para o NFT.
2. O leilão dura 7 dias.
3. O preço do NFT cai com o tempo
-4. Os participantes podem comprar depositando uma quantidade de ETH maior que valor corrente computado pelo contrato inteligente.
+4. Os participantes podem comprar depositando uma quantidade de ETH maior que o preço atual calculado pelo contrato inteligente.
5. O leilão termina quando alguém compra o NFT.
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
interface IERC721 {
function transferFrom(
@@ -23,49 +23,57 @@ interface IERC721 {
}
contract DutchAuction {
- event Buy(address winner, uint amount);
+ uint private constant DURATION = 7 days;
IERC721 public immutable nft;
uint public immutable nftId;
- address payable public seller;
- uint public startingPrice;
- uint public startAt;
- uint public expiresAt;
- uint public priceDeductionRate;
- address public winner;
+ address payable public immutable seller;
+ uint public immutable startingPrice;
+ uint public immutable startAt;
+ uint public immutable expiresAt;
+ uint public immutable discountRate;
constructor(
uint _startingPrice,
- uint _priceDeductionRate,
+ uint _discountRate,
address _nft,
uint _nftId
) {
seller = payable(msg.sender);
startingPrice = _startingPrice;
startAt = block.timestamp;
- expiresAt = block.timestamp + 7 days;
- priceDeductionRate = _priceDeductionRate;
+ expiresAt = block.timestamp + DURATION;
+ discountRate = _discountRate;
+
+ require(_startingPrice >= _discountRate * DURATION, "starting price < min");
nft = IERC721(_nft);
nftId = _nftId;
}
+ function getPrice() public view returns (uint) {
+ uint timeElapsed = block.timestamp - startAt;
+ uint discount = discountRate * timeElapsed;
+ return startingPrice - discount;
+ }
+
function buy() external payable {
require(block.timestamp < expiresAt, "auction expired");
- require(winner == address(0), "auction finished");
-
- uint timeElapsed = block.timestamp - startAt;
- uint deduction = priceDeductionRate * timeElapsed;
- uint price = startingPrice - deduction;
+ uint price = getPrice();
require(msg.value >= price, "ETH < price");
- winner = msg.sender;
nft.transferFrom(seller, msg.sender, nftId);
- seller.transfer(msg.value);
-
- emit Buy(msg.sender, msg.value);
+ uint refund = msg.value - price;
+ if (refund > 0) {
+ payable(msg.sender).transfer(refund);
+ }
+ selfdestruct(seller);
}
}
```
+
+## Teste no Remix
+
+- [DutchAuction.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmludGVyZmFjZSBJRVJDNzIxIHsKICAgIGZ1bmN0aW9uIHRyYW5zZmVyRnJvbSgKICAgICAgICBhZGRyZXNzIF9mcm9tLAogICAgICAgIGFkZHJlc3MgX3RvLAogICAgICAgIHVpbnQgX25mdElkCiAgICApIGV4dGVybmFsOwp9Cgpjb250cmFjdCBEdXRjaEF1Y3Rpb24gewogICAgdWludCBwcml2YXRlIGNvbnN0YW50IERVUkFUSU9OID0gNyBkYXlzOwoKICAgIElFUkM3MjEgcHVibGljIGltbXV0YWJsZSBuZnQ7CiAgICB1aW50IHB1YmxpYyBpbW11dGFibGUgbmZ0SWQ7CgogICAgYWRkcmVzcyBwYXlhYmxlIHB1YmxpYyBpbW11dGFibGUgc2VsbGVyOwogICAgdWludCBwdWJsaWMgaW1tdXRhYmxlIHN0YXJ0aW5nUHJpY2U7CiAgICB1aW50IHB1YmxpYyBpbW11dGFibGUgc3RhcnRBdDsKICAgIHVpbnQgcHVibGljIGltbXV0YWJsZSBleHBpcmVzQXQ7CiAgICB1aW50IHB1YmxpYyBpbW11dGFibGUgZGlzY291bnRSYXRlOwoKICAgIGNvbnN0cnVjdG9yKAogICAgICAgIHVpbnQgX3N0YXJ0aW5nUHJpY2UsCiAgICAgICAgdWludCBfZGlzY291bnRSYXRlLAogICAgICAgIGFkZHJlc3MgX25mdCwKICAgICAgICB1aW50IF9uZnRJZAogICAgKSB7CiAgICAgICAgc2VsbGVyID0gcGF5YWJsZShtc2cuc2VuZGVyKTsKICAgICAgICBzdGFydGluZ1ByaWNlID0gX3N0YXJ0aW5nUHJpY2U7CiAgICAgICAgc3RhcnRBdCA9IGJsb2NrLnRpbWVzdGFtcDsKICAgICAgICBleHBpcmVzQXQgPSBibG9jay50aW1lc3RhbXAgKyBEVVJBVElPTjsKICAgICAgICBkaXNjb3VudFJhdGUgPSBfZGlzY291bnRSYXRlOwoKICAgICAgICByZXF1aXJlKF9zdGFydGluZ1ByaWNlID49IF9kaXNjb3VudFJhdGUgKiBEVVJBVElPTiwgInN0YXJ0aW5nIHByaWNlIDwgbWluIik7CgogICAgICAgIG5mdCA9IElFUkM3MjEoX25mdCk7CiAgICAgICAgbmZ0SWQgPSBfbmZ0SWQ7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0UHJpY2UoKSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50KSB7CiAgICAgICAgdWludCB0aW1lRWxhcHNlZCA9IGJsb2NrLnRpbWVzdGFtcCAtIHN0YXJ0QXQ7CiAgICAgICAgdWludCBkaXNjb3VudCA9IGRpc2NvdW50UmF0ZSAqIHRpbWVFbGFwc2VkOwogICAgICAgIHJldHVybiBzdGFydGluZ1ByaWNlIC0gZGlzY291bnQ7CiAgICB9CgogICAgZnVuY3Rpb24gYnV5KCkgZXh0ZXJuYWwgcGF5YWJsZSB7CiAgICAgICAgcmVxdWlyZShibG9jay50aW1lc3RhbXAgPCBleHBpcmVzQXQsICJhdWN0aW9uIGV4cGlyZWQiKTsKCiAgICAgICAgdWludCBwcmljZSA9IGdldFByaWNlKCk7CiAgICAgICAgcmVxdWlyZShtc2cudmFsdWUgPj0gcHJpY2UsICJFVEggPCBwcmljZSIpOwoKICAgICAgICBuZnQudHJhbnNmZXJGcm9tKHNlbGxlciwgbXNnLnNlbmRlciwgbmZ0SWQpOwogICAgICAgIHVpbnQgcmVmdW5kID0gbXNnLnZhbHVlIC0gcHJpY2U7CiAgICAgICAgaWYgKHJlZnVuZCA+IDApIHsKICAgICAgICAgICAgcGF5YWJsZShtc2cuc2VuZGVyKS50cmFuc2ZlcihyZWZ1bmQpOwogICAgICAgIH0KICAgICAgICBzZWxmZGVzdHJ1Y3Qoc2VsbGVyKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/leilao-ingles.md b/src/exemplos/aplicacoes/leilao-ingles.md
index e9b49e3..56c8c8a 100644
--- a/src/exemplos/aplicacoes/leilao-ingles.md
+++ b/src/exemplos/aplicacoes/leilao-ingles.md
@@ -11,15 +11,19 @@ Leilão inglês de NFT.
#### Depois do leilão
-1. Quem deu o lance mais alto se torna o possuidor do NFT.
+1. Quem deu o lance mais alto se torna o novo proprietário do NFT.
2. O vendedor recebe o lance mais alto de ETH.
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
interface IERC721 {
- function transfer(address, uint) external;
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint tokenId
+ ) external;
function transferFrom(
address,
@@ -99,13 +103,17 @@ contract EnglishAuction {
ended = true;
if (highestBidder != address(0)) {
- nft.transfer(highestBidder, nftId);
+ nft.safeTransferFrom(address(this), highestBidder, nftId);
seller.transfer(highestBid);
} else {
- nft.transfer(seller, nftId);
+ nft.safeTransferFrom(address(this), seller, nftId);
}
emit End(highestBidder, highestBid);
}
}
```
+
+## Teste no Remix
+
+- [EnglishAuction.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmludGVyZmFjZSBJRVJDNzIxIHsKICAgIGZ1bmN0aW9uIHNhZmVUcmFuc2ZlckZyb20oCiAgICAgICAgYWRkcmVzcyBmcm9tLAogICAgICAgIGFkZHJlc3MgdG8sCiAgICAgICAgdWludCB0b2tlbklkCiAgICApIGV4dGVybmFsOwoKICAgIGZ1bmN0aW9uIHRyYW5zZmVyRnJvbSgKICAgICAgICBhZGRyZXNzLAogICAgICAgIGFkZHJlc3MsCiAgICAgICAgdWludAogICAgKSBleHRlcm5hbDsKfQoKY29udHJhY3QgRW5nbGlzaEF1Y3Rpb24gewogICAgZXZlbnQgU3RhcnQoKTsKICAgIGV2ZW50IEJpZChhZGRyZXNzIGluZGV4ZWQgc2VuZGVyLCB1aW50IGFtb3VudCk7CiAgICBldmVudCBXaXRoZHJhdyhhZGRyZXNzIGluZGV4ZWQgYmlkZGVyLCB1aW50IGFtb3VudCk7CiAgICBldmVudCBFbmQoYWRkcmVzcyB3aW5uZXIsIHVpbnQgYW1vdW50KTsKCiAgICBJRVJDNzIxIHB1YmxpYyBuZnQ7CiAgICB1aW50IHB1YmxpYyBuZnRJZDsKCiAgICBhZGRyZXNzIHBheWFibGUgcHVibGljIHNlbGxlcjsKICAgIHVpbnQgcHVibGljIGVuZEF0OwogICAgYm9vbCBwdWJsaWMgc3RhcnRlZDsKICAgIGJvb2wgcHVibGljIGVuZGVkOwoKICAgIGFkZHJlc3MgcHVibGljIGhpZ2hlc3RCaWRkZXI7CiAgICB1aW50IHB1YmxpYyBoaWdoZXN0QmlkOwogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQpIHB1YmxpYyBiaWRzOwoKICAgIGNvbnN0cnVjdG9yKAogICAgICAgIGFkZHJlc3MgX25mdCwKICAgICAgICB1aW50IF9uZnRJZCwKICAgICAgICB1aW50IF9zdGFydGluZ0JpZAogICAgKSB7CiAgICAgICAgbmZ0ID0gSUVSQzcyMShfbmZ0KTsKICAgICAgICBuZnRJZCA9IF9uZnRJZDsKCiAgICAgICAgc2VsbGVyID0gcGF5YWJsZShtc2cuc2VuZGVyKTsKICAgICAgICBoaWdoZXN0QmlkID0gX3N0YXJ0aW5nQmlkOwogICAgfQoKICAgIGZ1bmN0aW9uIHN0YXJ0KCkgZXh0ZXJuYWwgewogICAgICAgIHJlcXVpcmUoIXN0YXJ0ZWQsICJzdGFydGVkIik7CiAgICAgICAgcmVxdWlyZShtc2cuc2VuZGVyID09IHNlbGxlciwgIm5vdCBzZWxsZXIiKTsKCiAgICAgICAgbmZ0LnRyYW5zZmVyRnJvbShtc2cuc2VuZGVyLCBhZGRyZXNzKHRoaXMpLCBuZnRJZCk7CiAgICAgICAgc3RhcnRlZCA9IHRydWU7CiAgICAgICAgZW5kQXQgPSBibG9jay50aW1lc3RhbXAgKyA3IGRheXM7CgogICAgICAgIGVtaXQgU3RhcnQoKTsKICAgIH0KCiAgICBmdW5jdGlvbiBiaWQoKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgICAgICByZXF1aXJlKHN0YXJ0ZWQsICJub3Qgc3RhcnRlZCIpOwogICAgICAgIHJlcXVpcmUoYmxvY2sudGltZXN0YW1wIDwgZW5kQXQsICJlbmRlZCIpOwogICAgICAgIHJlcXVpcmUobXNnLnZhbHVlID4gaGlnaGVzdEJpZCwgInZhbHVlIDwgaGlnaGVzdCIpOwoKICAgICAgICBpZiAoaGlnaGVzdEJpZGRlciAhPSBhZGRyZXNzKDApKSB7CiAgICAgICAgICAgIGJpZHNbaGlnaGVzdEJpZGRlcl0gKz0gaGlnaGVzdEJpZDsKICAgICAgICB9CgogICAgICAgIGhpZ2hlc3RCaWRkZXIgPSBtc2cuc2VuZGVyOwogICAgICAgIGhpZ2hlc3RCaWQgPSBtc2cudmFsdWU7CgogICAgICAgIGVtaXQgQmlkKG1zZy5zZW5kZXIsIG1zZy52YWx1ZSk7CiAgICB9CgogICAgZnVuY3Rpb24gd2l0aGRyYXcoKSBleHRlcm5hbCB7CiAgICAgICAgdWludCBiYWwgPSBiaWRzW21zZy5zZW5kZXJdOwogICAgICAgIGJpZHNbbXNnLnNlbmRlcl0gPSAwOwogICAgICAgIHBheWFibGUobXNnLnNlbmRlcikudHJhbnNmZXIoYmFsKTsKCiAgICAgICAgZW1pdCBXaXRoZHJhdyhtc2cuc2VuZGVyLCBiYWwpOwogICAgfQoKICAgIGZ1bmN0aW9uIGVuZCgpIGV4dGVybmFsIHsKICAgICAgICByZXF1aXJlKHN0YXJ0ZWQsICJub3Qgc3RhcnRlZCIpOwogICAgICAgIHJlcXVpcmUoYmxvY2sudGltZXN0YW1wID49IGVuZEF0LCAibm90IGVuZGVkIik7CiAgICAgICAgcmVxdWlyZSghZW5kZWQsICJlbmRlZCIpOwoKICAgICAgICBlbmRlZCA9IHRydWU7CiAgICAgICAgaWYgKGhpZ2hlc3RCaWRkZXIgIT0gYWRkcmVzcygwKSkgewogICAgICAgICAgICBuZnQuc2FmZVRyYW5zZmVyRnJvbShhZGRyZXNzKHRoaXMpLCBoaWdoZXN0QmlkZGVyLCBuZnRJZCk7CiAgICAgICAgICAgIHNlbGxlci50cmFuc2ZlcihoaWdoZXN0QmlkKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBuZnQuc2FmZVRyYW5zZmVyRnJvbShhZGRyZXNzKHRoaXMpLCBzZWxsZXIsIG5mdElkKTsKICAgICAgICB9CgogICAgICAgIGVtaXQgRW5kKGhpZ2hlc3RCaWRkZXIsIGhpZ2hlc3RCaWQpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/mapping-iteravel.md b/src/exemplos/aplicacoes/mapping-iteravel.md
index 7ce9d80..2fb3f65 100644
--- a/src/exemplos/aplicacoes/mapping-iteravel.md
+++ b/src/exemplos/aplicacoes/mapping-iteravel.md
@@ -4,10 +4,10 @@ Você não pode iterar através de um `mapping`. Aqui está um exemplo de como c
```solidity
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.3;
+pragma solidity ^0.8.20;
library IterableMapping {
- // Mapping iterável do endereço ao uint;
+ // Mapeamento iterável de endereço para uint;
struct Map {
address[] keys;
mapping(address => uint) values;
@@ -90,3 +90,7 @@ contract TestIterableMap {
}
}
```
+
+## Teste no Remix
+
+- [IterableMapping.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmxpYnJhcnkgSXRlcmFibGVNYXBwaW5nIHsKICAgIC8vIE1hcGVhbWVudG8gaXRlcmF2ZWwgZGUgZW5kZXJlY28gcGFyYSB1aW50OwogICAgc3RydWN0IE1hcCB7CiAgICAgICAgYWRkcmVzc1tdIGtleXM7CiAgICAgICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQpIHZhbHVlczsKICAgICAgICBtYXBwaW5nKGFkZHJlc3MgPT4gdWludCkgaW5kZXhPZjsKICAgICAgICBtYXBwaW5nKGFkZHJlc3MgPT4gYm9vbCkgaW5zZXJ0ZWQ7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0KE1hcCBzdG9yYWdlIG1hcCwgYWRkcmVzcyBrZXkpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQpIHsKICAgICAgICByZXR1cm4gbWFwLnZhbHVlc1trZXldOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldEtleUF0SW5kZXgoTWFwIHN0b3JhZ2UgbWFwLCB1aW50IGluZGV4KSBwdWJsaWMgdmlldyByZXR1cm5zIChhZGRyZXNzKSB7CiAgICAgICAgcmV0dXJuIG1hcC5rZXlzW2luZGV4XTsKICAgIH0KCiAgICBmdW5jdGlvbiBzaXplKE1hcCBzdG9yYWdlIG1hcCkgcHVibGljIHZpZXcgcmV0dXJucyAodWludCkgewogICAgICAgIHJldHVybiBtYXAua2V5cy5sZW5ndGg7CiAgICB9CgogICAgZnVuY3Rpb24gc2V0KAogICAgICAgIE1hcCBzdG9yYWdlIG1hcCwKICAgICAgICBhZGRyZXNzIGtleSwKICAgICAgICB1aW50IHZhbAogICAgKSBwdWJsaWMgewogICAgICAgIGlmIChtYXAuaW5zZXJ0ZWRba2V5XSkgewogICAgICAgICAgICBtYXAudmFsdWVzW2tleV0gPSB2YWw7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgbWFwLmluc2VydGVkW2tleV0gPSB0cnVlOwogICAgICAgICAgICBtYXAudmFsdWVzW2tleV0gPSB2YWw7CiAgICAgICAgICAgIG1hcC5pbmRleE9mW2tleV0gPSBtYXAua2V5cy5sZW5ndGg7CiAgICAgICAgICAgIG1hcC5rZXlzLnB1c2goa2V5KTsKICAgICAgICB9CiAgICB9CgogICAgZnVuY3Rpb24gcmVtb3ZlKE1hcCBzdG9yYWdlIG1hcCwgYWRkcmVzcyBrZXkpIHB1YmxpYyB7CiAgICAgICAgaWYgKCFtYXAuaW5zZXJ0ZWRba2V5XSkgewogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQoKICAgICAgICBkZWxldGUgbWFwLmluc2VydGVkW2tleV07CiAgICAgICAgZGVsZXRlIG1hcC52YWx1ZXNba2V5XTsKCiAgICAgICAgdWludCBpbmRleCA9IG1hcC5pbmRleE9mW2tleV07CiAgICAgICAgdWludCBsYXN0SW5kZXggPSBtYXAua2V5cy5sZW5ndGggLSAxOwogICAgICAgIGFkZHJlc3MgbGFzdEtleSA9IG1hcC5rZXlzW2xhc3RJbmRleF07CgogICAgICAgIG1hcC5pbmRleE9mW2xhc3RLZXldID0gaW5kZXg7CiAgICAgICAgZGVsZXRlIG1hcC5pbmRleE9mW2tleV07CgogICAgICAgIG1hcC5rZXlzW2luZGV4XSA9IGxhc3RLZXk7CiAgICAgICAgbWFwLmtleXMucG9wKCk7CiAgICB9Cn0KCmNvbnRyYWN0IFRlc3RJdGVyYWJsZU1hcCB7CiAgICB1c2luZyBJdGVyYWJsZU1hcHBpbmcgZm9yIEl0ZXJhYmxlTWFwcGluZy5NYXA7CgogICAgSXRlcmFibGVNYXBwaW5nLk1hcCBwcml2YXRlIG1hcDsKCiAgICBmdW5jdGlvbiB0ZXN0SXRlcmFibGVNYXAoKSBwdWJsaWMgewogICAgICAgIG1hcC5zZXQoYWRkcmVzcygwKSwgMCk7CiAgICAgICAgbWFwLnNldChhZGRyZXNzKDEpLCAxMDApOwogICAgICAgIG1hcC5zZXQoYWRkcmVzcygyKSwgMjAwKTsgLy8gaW5zZXJ0CiAgICAgICAgbWFwLnNldChhZGRyZXNzKDIpLCAyMDApOyAvLyB1cGRhdGUKICAgICAgICBtYXAuc2V0KGFkZHJlc3MoMyksIDMwMCk7CgogICAgICAgIGZvciAodWludCBpID0gMDsgaSA8IG1hcC5zaXplKCk7IGkrKykgewogICAgICAgICAgICBhZGRyZXNzIGtleSA9IG1hcC5nZXRLZXlBdEluZGV4KGkpOwoKICAgICAgICAgICAgYXNzZXJ0KG1hcC5nZXQoa2V5KSA9PSBpICogMTAwKTsKICAgICAgICB9CgogICAgICAgIG1hcC5yZW1vdmUoYWRkcmVzcygxKSk7CgogICAgICAgIC8vIGtleXMgPSBbYWRkcmVzcygwKSwgYWRkcmVzcygzKSwgYWRkcmVzcygyKV0KICAgICAgICBhc3NlcnQobWFwLnNpemUoKSA9PSAzKTsKICAgICAgICBhc3NlcnQobWFwLmdldEtleUF0SW5kZXgoMCkgPT0gYWRkcmVzcygwKSk7CiAgICAgICAgYXNzZXJ0KG1hcC5nZXRLZXlBdEluZGV4KDEpID09IGFkZHJlc3MoMykpOwogICAgICAgIGFzc2VydChtYXAuZ2V0S2V5QXRJbmRleCgyKSA9PSBhZGRyZXNzKDIpKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
\ No newline at end of file
diff --git a/src/exemplos/aplicacoes/multi-chamadas.md b/src/exemplos/aplicacoes/multi-chamadas.md
new file mode 100644
index 0000000..dcf3947
--- /dev/null
+++ b/src/exemplos/aplicacoes/multi-chamadas.md
@@ -0,0 +1,50 @@
+# Multi chamadas
+
+Um exemplo de contrato que agrega várias consultas usando um loop `for` e `staticcall`.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+contract MultiCall {
+ function multiCall(address[] calldata targets, bytes[] calldata data)
+ external
+ view
+ returns (bytes[] memory)
+ {
+ require(targets.length == data.length, "target length != data length");
+
+ bytes[] memory results = new bytes[](data.length);
+
+ for (uint i; i < targets.length; i++) {
+ (bool success, bytes memory result) = targets[i].staticcall(data[i]);
+ require(success, "call failed");
+ results[i] = result;
+ }
+
+ return results;
+ }
+}
+```
+
+Contrato para testar `MultiCall`
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+contract TestMultiCall {
+ function test(uint _i) external pure returns (uint) {
+ return _i;
+ }
+
+ function getData(uint _i) external pure returns (bytes memory) {
+ return abi.encodeWithSelector(this.test.selector, _i);
+ }
+}
+```
+
+## Teste no Remix
+
+- [MultiCall.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IE11bHRpQ2FsbCB7CiAgICBmdW5jdGlvbiBtdWx0aUNhbGwoYWRkcmVzc1tdIGNhbGxkYXRhIHRhcmdldHMsIGJ5dGVzW10gY2FsbGRhdGEgZGF0YSkKICAgICAgICBleHRlcm5hbAogICAgICAgIHZpZXcKICAgICAgICByZXR1cm5zIChieXRlc1tdIG1lbW9yeSkKICAgIHsKICAgICAgICByZXF1aXJlKHRhcmdldHMubGVuZ3RoID09IGRhdGEubGVuZ3RoLCAidGFyZ2V0IGxlbmd0aCAhPSBkYXRhIGxlbmd0aCIpOwoKICAgICAgICBieXRlc1tdIG1lbW9yeSByZXN1bHRzID0gbmV3IGJ5dGVzW10oZGF0YS5sZW5ndGgpOwoKICAgICAgICBmb3IgKHVpbnQgaTsgaSA8IHRhcmdldHMubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgKGJvb2wgc3VjY2VzcywgYnl0ZXMgbWVtb3J5IHJlc3VsdCkgPSB0YXJnZXRzW2ldLnN0YXRpY2NhbGwoZGF0YVtpXSk7CiAgICAgICAgICAgIHJlcXVpcmUoc3VjY2VzcywgImNhbGwgZmFpbGVkIik7CiAgICAgICAgICAgIHJlc3VsdHNbaV0gPSByZXN1bHQ7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gcmVzdWx0czsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
+- [TestMultiCall.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IFRlc3RNdWx0aUNhbGwgewogICAgZnVuY3Rpb24gdGVzdCh1aW50IF9pKSBleHRlcm5hbCBwdXJlIHJldHVybnMgKHVpbnQpIHsKICAgICAgICByZXR1cm4gX2k7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0RGF0YSh1aW50IF9pKSBleHRlcm5hbCBwdXJlIHJldHVybnMgKGJ5dGVzIG1lbW9yeSkgewogICAgICAgIHJldHVybiBhYmkuZW5jb2RlV2l0aFNlbGVjdG9yKHRoaXMudGVzdC5zZWxlY3RvciwgX2kpOwogICAgfQp9&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/multi-delegatecall.md b/src/exemplos/aplicacoes/multi-delegatecall.md
new file mode 100644
index 0000000..a2ae269
--- /dev/null
+++ b/src/exemplos/aplicacoes/multi-delegatecall.md
@@ -0,0 +1,72 @@
+# Multi Delegatecall
+
+Um exemplo de chamada de várias funções com uma única transação, usando `delegatecall`.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+contract MultiDelegatecall {
+ error DelegatecallFailed();
+
+ function multiDelegatecall(bytes[] memory data)
+ external
+ payable
+ returns (bytes[] memory results)
+ {
+ results = new bytes[](data.length);
+
+ for (uint i; i < data.length; i++) {
+ (bool ok, bytes memory res) = address(this).delegatecall(data[i]);
+ if (!ok) {
+ revert DelegatecallFailed();
+ }
+ results[i] = res;
+ }
+ }
+}
+
+// Por que usar a chamada multi delegatecall? Por que não multi call?
+// alice -> multi call --- chama ---> test (msg.sender = multi call)
+// alice -> test --- delegatecall ---> test (msg.sender = alice)
+contract TestMultiDelegatecall is MultiDelegatecall {
+ event Log(address caller, string func, uint i);
+
+ function func1(uint x, uint y) external {
+ // msg.sender = alice
+ emit Log(msg.sender, "func1", x + y);
+ }
+
+ function func2() external returns (uint) {
+ // msg.sender = alice
+ emit Log(msg.sender, "func2", 2);
+ return 111;
+ }
+
+ mapping(address => uint) public balanceOf;
+
+ // AVISO: código inseguro quando usado em combinação com multi-delegatecall
+ // o usuário pode cunhar várias vezes pelo preço de msg.value
+ function mint() external payable {
+ balanceOf[msg.sender] += msg.value;
+ }
+}
+
+contract Helper {
+ function getFunc1Data(uint x, uint y) external pure returns (bytes memory) {
+ return abi.encodeWithSelector(TestMultiDelegatecall.func1.selector, x, y);
+ }
+
+ function getFunc2Data() external pure returns (bytes memory) {
+ return abi.encodeWithSelector(TestMultiDelegatecall.func2.selector);
+ }
+
+ function getMintData() external pure returns (bytes memory) {
+ return abi.encodeWithSelector(TestMultiDelegatecall.mint.selector);
+ }
+}
+```
+
+## Teste no Remix
+
+- [MultiDelegatecall.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmNvbnRyYWN0IE11bHRpRGVsZWdhdGVjYWxsIHsKICAgIGVycm9yIERlbGVnYXRlY2FsbEZhaWxlZCgpOwoKICAgIGZ1bmN0aW9uIG11bHRpRGVsZWdhdGVjYWxsKGJ5dGVzW10gbWVtb3J5IGRhdGEpCiAgICAgICAgZXh0ZXJuYWwKICAgICAgICBwYXlhYmxlCiAgICAgICAgcmV0dXJucyAoYnl0ZXNbXSBtZW1vcnkgcmVzdWx0cykKICAgIHsKICAgICAgICByZXN1bHRzID0gbmV3IGJ5dGVzW10oZGF0YS5sZW5ndGgpOwoKICAgICAgICBmb3IgKHVpbnQgaTsgaSA8IGRhdGEubGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgKGJvb2wgb2ssIGJ5dGVzIG1lbW9yeSByZXMpID0gYWRkcmVzcyh0aGlzKS5kZWxlZ2F0ZWNhbGwoZGF0YVtpXSk7CiAgICAgICAgICAgIGlmICghb2spIHsKICAgICAgICAgICAgICAgIHJldmVydCBEZWxlZ2F0ZWNhbGxGYWlsZWQoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXN1bHRzW2ldID0gcmVzOwogICAgICAgIH0KICAgIH0KfQoKLy8gUG9yIHF1ZSB1c2FyIGEgY2hhbWFkYSBtdWx0aSBkZWxlZ2F0ZWNhbGw/IFBvciBxdWUgbmFvIG11bHRpIGNhbGw/Ci8vIGFsaWNlIC0+IG11bHRpIGNhbGwgLS0tIGNoYW1hIC0tLT4gdGVzdCAobXNnLnNlbmRlciA9IG11bHRpIGNhbGwpCi8vIGFsaWNlIC0+IHRlc3QgLS0tIGRlbGVnYXRlY2FsbCAtLS0+IHRlc3QgKG1zZy5zZW5kZXIgPSBhbGljZSkKY29udHJhY3QgVGVzdE11bHRpRGVsZWdhdGVjYWxsIGlzIE11bHRpRGVsZWdhdGVjYWxsIHsKICAgIGV2ZW50IExvZyhhZGRyZXNzIGNhbGxlciwgc3RyaW5nIGZ1bmMsIHVpbnQgaSk7CgogICAgZnVuY3Rpb24gZnVuYzEodWludCB4LCB1aW50IHkpIGV4dGVybmFsIHsKICAgICAgICAvLyBtc2cuc2VuZGVyID0gYWxpY2UKICAgICAgICBlbWl0IExvZyhtc2cuc2VuZGVyLCAiZnVuYzEiLCB4ICsgeSk7CiAgICB9CgogICAgZnVuY3Rpb24gZnVuYzIoKSBleHRlcm5hbCByZXR1cm5zICh1aW50KSB7CiAgICAgICAgLy8gbXNnLnNlbmRlciA9IGFsaWNlCiAgICAgICAgZW1pdCBMb2cobXNnLnNlbmRlciwgImZ1bmMyIiwgMik7CiAgICAgICAgcmV0dXJuIDExMTsKICAgIH0KCiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gdWludCkgcHVibGljIGJhbGFuY2VPZjsKCiAgICAvLyBBVklTTzogY29kaWdvIGluc2VndXJvIHF1YW5kbyB1c2FkbyBlbSBjb21iaW5hY2FvIGNvbSBtdWx0aS1kZWxlZ2F0ZWNhbGwKICAgIC8vIG8gdXN1YXJpbyBwb2RlIGN1bmhhciB2YXJpYXMgdmV6ZXMgcGVsbyBwcmVjbyBkZSBtc2cudmFsdWUKICAgIGZ1bmN0aW9uIG1pbnQoKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgICAgICBiYWxhbmNlT2ZbbXNnLnNlbmRlcl0gKz0gbXNnLnZhbHVlOwogICAgfQp9Cgpjb250cmFjdCBIZWxwZXIgewogICAgZnVuY3Rpb24gZ2V0RnVuYzFEYXRhKHVpbnQgeCwgdWludCB5KSBleHRlcm5hbCBwdXJlIHJldHVybnMgKGJ5dGVzIG1lbW9yeSkgewogICAgICAgIHJldHVybiBhYmkuZW5jb2RlV2l0aFNlbGVjdG9yKFRlc3RNdWx0aURlbGVnYXRlY2FsbC5mdW5jMS5zZWxlY3RvciwgeCwgeSk7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0RnVuYzJEYXRhKCkgZXh0ZXJuYWwgcHVyZSByZXR1cm5zIChieXRlcyBtZW1vcnkpIHsKICAgICAgICByZXR1cm4gYWJpLmVuY29kZVdpdGhTZWxlY3RvcihUZXN0TXVsdGlEZWxlZ2F0ZWNhbGwuZnVuYzIuc2VsZWN0b3IpOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldE1pbnREYXRhKCkgZXh0ZXJuYWwgcHVyZSByZXR1cm5zIChieXRlcyBtZW1vcnkpIHsKICAgICAgICByZXR1cm4gYWJpLmVuY29kZVdpdGhTZWxlY3RvcihUZXN0TXVsdGlEZWxlZ2F0ZWNhbGwubWludC5zZWxlY3Rvcik7CiAgICB9Cn0=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/proxy-atualizavel.md b/src/exemplos/aplicacoes/proxy-atualizavel.md
new file mode 100644
index 0000000..85655da
--- /dev/null
+++ b/src/exemplos/aplicacoes/proxy-atualizavel.md
@@ -0,0 +1,262 @@
+# Proxy atualizável
+
+Exemplo de contrato de proxy atualizável. Nunca use isso em produção.
+
+Este exemplo mostra
+
+- como usar `delegatecalle` retornar dados quando `fallback` é chamado.
+- como armazenar o endereço de `admin` e `implementation` em um slot específico.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+// Padrão de proxy atualizável transparente
+
+contract CounterV1 {
+ uint public count;
+
+ function inc() external {
+ count += 1;
+ }
+}
+
+contract CounterV2 {
+ uint public count;
+
+ function inc() external {
+ count += 1;
+ }
+
+ function dec() external {
+ count -= 1;
+ }
+}
+
+contract BuggyProxy {
+ address public implementation;
+ address public admin;
+
+ constructor() {
+ admin = msg.sender;
+ }
+
+ function _delegate() private {
+ (bool ok, bytes memory res) = implementation.delegatecall(msg.data);
+ require(ok, "delegatecall failed");
+ }
+
+ fallback() external payable {
+ _delegate();
+ }
+
+ receive() external payable {
+ _delegate();
+ }
+
+ function upgradeTo(address _implementation) external {
+ require(msg.sender == admin, "not authorized");
+ implementation = _implementation;
+ }
+}
+
+contract Dev {
+ function selectors()
+ external
+ view
+ returns (
+ bytes4,
+ bytes4,
+ bytes4
+ )
+ {
+ return (
+ Proxy.admin.selector,
+ Proxy.implementation.selector,
+ Proxy.upgradeTo.selector
+ );
+ }
+}
+
+contract Proxy {
+ // Todas as funções/variáveis devem ser privadas, encaminhe todas as chamadas para fallback
+
+ // -1 para pré-imagem desconhecida
+ // 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
+ bytes32 private constant IMPLEMENTATION_SLOT =
+ bytes32(uint(keccak256("eip1967.proxy.implementation")) - 1);
+ // 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
+ bytes32 private constant ADMIN_SLOT =
+ bytes32(uint(keccak256("eip1967.proxy.admin")) - 1);
+
+ constructor() {
+ _setAdmin(msg.sender);
+ }
+
+ modifier ifAdmin() {
+ if (msg.sender == _getAdmin()) {
+ _;
+ } else {
+ _fallback();
+ }
+ }
+
+ function _getAdmin() private view returns (address) {
+ return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
+ }
+
+ function _setAdmin(address _admin) private {
+ require(_admin != address(0), "admin = zero address");
+ StorageSlot.getAddressSlot(ADMIN_SLOT).value = _admin;
+ }
+
+ function _getImplementation() private view returns (address) {
+ return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
+ }
+
+ function _setImplementation(address _implementation) private {
+ require(_implementation.code.length > 0, "implementation is not contract");
+ StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = _implementation;
+ }
+
+ // Interface do administrador//
+ function changeAdmin(address _admin) external ifAdmin {
+ _setAdmin(_admin);
+ }
+
+ // 0x3659cfe6
+ function upgradeTo(address _implementation) external ifAdmin {
+ _setImplementation(_implementation);
+ }
+
+ // 0xf851a440
+ function admin() external ifAdmin returns (address) {
+ return _getAdmin();
+ }
+
+ // 0x5c60da1b
+ function implementation() external ifAdmin returns (address) {
+ return _getImplementation();
+ }
+
+ // Interface do usuário //
+ function _delegate(address _implementation) internal virtual {
+ assembly {
+ // Copia msg.data. Assumimos o controle total da memória nesta montagem em linha
+ // bloquear porque não retornará ao código Solidity. Nós sobrescrevemos o
+ // Nós sobrescrevemos o bloco de rascunho de Solidity na posição de memória 0.
+
+
+ // calldatacopy(t, f, s) - copia S bytes de calldata na posição f para mem na posição t
+ // calldatasize() - tamanho dos dados da chamada em bytes
+ calldatacopy(0, 0, calldatasize())
+
+ // Chama a implementação.
+ // out and outsize são 0 porque ainda não sabemos o tamanho.
+
+ // delegatecall(g, a, in, insize, out, outsize) -
+ // - contrato de chamada no endereço a
+ // - com entrada mem[in…(in+insize))
+ // - fornecimento de gás g
+ // - área de saída mem[out…(out+outsize))
+ // - retornando 0 em caso de erro (por exemplo, falta de gás) e 1 em caso de sucesso
+ let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)
+
+ // Copie os dados retornados.
+ // returndatacopy(t, f, s) - copia S bytes de returndata na posição f para mem na posição t
+ // returndatasize() - tamanho do último returndata
+ returndatacopy(0, 0, returndatasize())
+
+ switch result
+ // delegatecall retorna 0 em caso de erro.
+ case 0 {
+ // revert(p, s) - finaliza a execução, reverte mudanças de estado, retorna dados mem[p…(p+s))
+ revert(0, returndatasize())
+ }
+ default {
+ // return(p, s) - finaliza a execução, retorna dados mem[p…(p+s))
+ return(0, returndatasize())
+ }
+ }
+ }
+
+ function _fallback() private {
+ _delegate(_getImplementation());
+ }
+
+ fallback() external payable {
+ _fallback();
+ }
+
+ receive() external payable {
+ _fallback();
+ }
+}
+
+contract ProxyAdmin {
+ address public owner;
+
+ constructor() {
+ owner = msg.sender;
+ }
+
+ modifier onlyOwner() {
+ require(msg.sender == owner, "not owner");
+ _;
+ }
+
+ function getProxyAdmin(address proxy) external view returns (address) {
+ (bool ok, bytes memory res) = proxy.staticcall(
+ abi.encodeCall(Proxy.implementation, ())
+ );
+ require(ok, "call failed");
+ return abi.decode(res, (address));
+ }
+
+ function getProxyImplementation(address proxy) external view returns (address) {
+ (bool ok, bytes memory res) = proxy.staticcall(abi.encodeCall(Proxy.admin, ()));
+ require(ok, "call failed");
+ return abi.decode(res, (address));
+ }
+
+ function changeProxyAdmin(address payable proxy, address admin) external onlyOwner {
+ Proxy(proxy).changeAdmin(admin);
+ }
+
+ function upgrade(address payable proxy, address implementation) external onlyOwner {
+ Proxy(proxy).upgradeTo(implementation);
+ }
+}
+
+library StorageSlot {
+ struct AddressSlot {
+ address value;
+ }
+
+ function getAddressSlot(bytes32 slot)
+ internal
+ pure
+ returns (AddressSlot storage r)
+ {
+ assembly {
+ r.slot := slot
+ }
+ }
+}
+
+contract TestSlot {
+ bytes32 public constant slot = keccak256("TEST_SLOT");
+
+ function getSlot() external view returns (address) {
+ return StorageSlot.getAddressSlot(slot).value;
+ }
+
+ function writeSlot(address _addr) external {
+ StorageSlot.getAddressSlot(slot).value = _addr;
+ }
+}
+```
+
+## Teste no Remix
+
+- [UpgradeableProxy.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCi8vIFBhZHJhbyBkZSBwcm94eSBhdHVhbGl6YXZlbCB0cmFuc3BhcmVudGUKCmNvbnRyYWN0IENvdW50ZXJWMSB7CiAgICB1aW50IHB1YmxpYyBjb3VudDsKCiAgICBmdW5jdGlvbiBpbmMoKSBleHRlcm5hbCB7CiAgICAgICAgY291bnQgKz0gMTsKICAgIH0KfQoKY29udHJhY3QgQ291bnRlclYyIHsKICAgIHVpbnQgcHVibGljIGNvdW50OwoKICAgIGZ1bmN0aW9uIGluYygpIGV4dGVybmFsIHsKICAgICAgICBjb3VudCArPSAxOwogICAgfQoKICAgIGZ1bmN0aW9uIGRlYygpIGV4dGVybmFsIHsKICAgICAgICBjb3VudCAtPSAxOwogICAgfQp9Cgpjb250cmFjdCBCdWdneVByb3h5IHsKICAgIGFkZHJlc3MgcHVibGljIGltcGxlbWVudGF0aW9uOwogICAgYWRkcmVzcyBwdWJsaWMgYWRtaW47CgogICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgYWRtaW4gPSBtc2cuc2VuZGVyOwogICAgfQoKICAgIGZ1bmN0aW9uIF9kZWxlZ2F0ZSgpIHByaXZhdGUgewogICAgICAgIChib29sIG9rLCBieXRlcyBtZW1vcnkgcmVzKSA9IGltcGxlbWVudGF0aW9uLmRlbGVnYXRlY2FsbChtc2cuZGF0YSk7CiAgICAgICAgcmVxdWlyZShvaywgImRlbGVnYXRlY2FsbCBmYWlsZWQiKTsKICAgIH0KCiAgICBmYWxsYmFjaygpIGV4dGVybmFsIHBheWFibGUgewogICAgICAgIF9kZWxlZ2F0ZSgpOwogICAgfQoKICAgIHJlY2VpdmUoKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgICAgICBfZGVsZWdhdGUoKTsKICAgIH0KCiAgICBmdW5jdGlvbiB1cGdyYWRlVG8oYWRkcmVzcyBfaW1wbGVtZW50YXRpb24pIGV4dGVybmFsIHsKICAgICAgICByZXF1aXJlKG1zZy5zZW5kZXIgPT0gYWRtaW4sICJub3QgYXV0aG9yaXplZCIpOwogICAgICAgIGltcGxlbWVudGF0aW9uID0gX2ltcGxlbWVudGF0aW9uOwogICAgfQp9Cgpjb250cmFjdCBEZXYgewogICAgZnVuY3Rpb24gc2VsZWN0b3JzKCkKICAgICAgICBleHRlcm5hbAogICAgICAgIHZpZXcKICAgICAgICByZXR1cm5zICgKICAgICAgICAgICAgYnl0ZXM0LAogICAgICAgICAgICBieXRlczQsCiAgICAgICAgICAgIGJ5dGVzNAogICAgICAgICkKICAgIHsKICAgICAgICByZXR1cm4gKAogICAgICAgICAgICBQcm94eS5hZG1pbi5zZWxlY3RvciwKICAgICAgICAgICAgUHJveHkuaW1wbGVtZW50YXRpb24uc2VsZWN0b3IsCiAgICAgICAgICAgIFByb3h5LnVwZ3JhZGVUby5zZWxlY3RvcgogICAgICAgICk7CiAgICB9Cn0KCmNvbnRyYWN0IFByb3h5IHsKICAgIC8vIFRvZGFzIGFzIGZ1bmNvZXMvdmFyaWF2ZWlzID8/ZGV2ZW0gc2VyIHByaXZhZGFzLCBlbmNhbWluaGUgdG9kYXMgYXMgY2hhbWFkYXMgcGFyYSBmYWxsYmFjawoKICAgIC8vIC0xIHBhcmEgcHJlLWltYWdlbSBkZXNjb25oZWNpZGEKICAgIC8vIDB4MzYwODk0YTEzYmExYTMyMTA2NjdjODI4NDkyZGI5OGRjYTNlMjA3NmNjMzczNWE5MjBhM2NhNTA1ZDM4MmJiYwogICAgYnl0ZXMzMiBwcml2YXRlIGNvbnN0YW50IElNUExFTUVOVEFUSU9OX1NMT1QgPQogICAgICAgIGJ5dGVzMzIodWludChrZWNjYWsyNTYoImVpcDE5NjcucHJveHkuaW1wbGVtZW50YXRpb24iKSkgLSAxKTsKICAgIC8vIDB4YjUzMTI3Njg0YTU2OGIzMTczYWUxM2I5ZjhhNjAxNmUyNDNlNjNiNmU4ZWUxMTc4ZDZhNzE3ODUwYjVkNjEwMwogICAgYnl0ZXMzMiBwcml2YXRlIGNvbnN0YW50IEFETUlOX1NMT1QgPQogICAgICAgIGJ5dGVzMzIodWludChrZWNjYWsyNTYoImVpcDE5NjcucHJveHkuYWRtaW4iKSkgLSAxKTsKCiAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICBfc2V0QWRtaW4obXNnLnNlbmRlcik7CiAgICB9CgogICAgbW9kaWZpZXIgaWZBZG1pbigpIHsKICAgICAgICBpZiAobXNnLnNlbmRlciA9PSBfZ2V0QWRtaW4oKSkgewogICAgICAgICAgICBfOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIF9mYWxsYmFjaygpOwogICAgICAgIH0KICAgIH0KCiAgICBmdW5jdGlvbiBfZ2V0QWRtaW4oKSBwcml2YXRlIHZpZXcgcmV0dXJucyAoYWRkcmVzcykgewogICAgICAgIHJldHVybiBTdG9yYWdlU2xvdC5nZXRBZGRyZXNzU2xvdChBRE1JTl9TTE9UKS52YWx1ZTsKICAgIH0KCiAgICBmdW5jdGlvbiBfc2V0QWRtaW4oYWRkcmVzcyBfYWRtaW4pIHByaXZhdGUgewogICAgICAgIHJlcXVpcmUoX2FkbWluICE9IGFkZHJlc3MoMCksICJhZG1pbiA9IHplcm8gYWRkcmVzcyIpOwogICAgICAgIFN0b3JhZ2VTbG90LmdldEFkZHJlc3NTbG90KEFETUlOX1NMT1QpLnZhbHVlID0gX2FkbWluOwogICAgfQoKICAgIGZ1bmN0aW9uIF9nZXRJbXBsZW1lbnRhdGlvbigpIHByaXZhdGUgdmlldyByZXR1cm5zIChhZGRyZXNzKSB7CiAgICAgICAgcmV0dXJuIFN0b3JhZ2VTbG90LmdldEFkZHJlc3NTbG90KElNUExFTUVOVEFUSU9OX1NMT1QpLnZhbHVlOwogICAgfQoKICAgIGZ1bmN0aW9uIF9zZXRJbXBsZW1lbnRhdGlvbihhZGRyZXNzIF9pbXBsZW1lbnRhdGlvbikgcHJpdmF0ZSB7CiAgICAgICAgcmVxdWlyZShfaW1wbGVtZW50YXRpb24uY29kZS5sZW5ndGggPiAwLCAiaW1wbGVtZW50YXRpb24gaXMgbm90IGNvbnRyYWN0Iik7CiAgICAgICAgU3RvcmFnZVNsb3QuZ2V0QWRkcmVzc1Nsb3QoSU1QTEVNRU5UQVRJT05fU0xPVCkudmFsdWUgPSBfaW1wbGVtZW50YXRpb247CiAgICB9CgogICAgLy8gSW50ZXJmYWNlIGRvIGFkbWluaXN0cmFkb3IvLwogICAgZnVuY3Rpb24gY2hhbmdlQWRtaW4oYWRkcmVzcyBfYWRtaW4pIGV4dGVybmFsIGlmQWRtaW4gewogICAgICAgIF9zZXRBZG1pbihfYWRtaW4pOwogICAgfQoKICAgIC8vIDB4MzY1OWNmZTYKICAgIGZ1bmN0aW9uIHVwZ3JhZGVUbyhhZGRyZXNzIF9pbXBsZW1lbnRhdGlvbikgZXh0ZXJuYWwgaWZBZG1pbiB7CiAgICAgICAgX3NldEltcGxlbWVudGF0aW9uKF9pbXBsZW1lbnRhdGlvbik7CiAgICB9CgogICAgLy8gMHhmODUxYTQ0MAogICAgZnVuY3Rpb24gYWRtaW4oKSBleHRlcm5hbCBpZkFkbWluIHJldHVybnMgKGFkZHJlc3MpIHsKICAgICAgICByZXR1cm4gX2dldEFkbWluKCk7CiAgICB9CgogICAgLy8gMHg1YzYwZGExYgogICAgZnVuY3Rpb24gaW1wbGVtZW50YXRpb24oKSBleHRlcm5hbCBpZkFkbWluIHJldHVybnMgKGFkZHJlc3MpIHsKICAgICAgICByZXR1cm4gX2dldEltcGxlbWVudGF0aW9uKCk7CiAgICB9CgogICAgLy8gSW50ZXJmYWNlIGRvIHVzdWFyaW8gLy8KICAgIGZ1bmN0aW9uIF9kZWxlZ2F0ZShhZGRyZXNzIF9pbXBsZW1lbnRhdGlvbikgaW50ZXJuYWwgdmlydHVhbCB7CiAgICAgICAgYXNzZW1ibHkgewogICAgICAgICAgICAvLyBDb3BpYSBtc2cuZGF0YS4gQXNzdW1pbW9zIG8gY29udHJvbGUgdG90YWwgZGEgbWVtb3JpYSBuZXN0YSBtb250YWdlbSBlbSBsaW5oYQogICAgICAgICAgICAvLyBibG9xdWVhciBwb3JxdWUgbmFvIHJldG9ybmFyYSBhbyBjb2RpZ28gU29saWRpdHkuIE5vcyBzb2JyZXNjcmV2ZW1vcyBvCiAgICAgICAgICAgIC8vIE5vcyBzb2JyZXNjcmV2ZW1vcyBvIGJsb2NvIGRlIHJhc2N1bmhvIGRlIFNvbGlkaXR5IG5hIHBvc2ljYW8gZGUgbWVtb3JpYSAwLgoKCiAgICAgICAgICAgIC8vIGNhbGxkYXRhY29weSh0LCBmLCBzKSAtIGNvcGlhIFMgYnl0ZXMgZGUgY2FsbGRhdGEgbmEgcG9zaWNhbyBmIHBhcmEgbWVtIG5hIHBvc2ljYW8gdAogICAgICAgICAgICAvLyBjYWxsZGF0YXNpemUoKSAtIHRhbWFuaG8gZG9zIGRhZG9zIGRhIGNoYW1hZGEgZW0gYnl0ZXMKICAgICAgICAgICAgY2FsbGRhdGFjb3B5KDAsIDAsIGNhbGxkYXRhc2l6ZSgpKQoKICAgICAgICAgICAgLy8gQ2hhbWEgYSBpbXBsZW1lbnRhY2FvLgogICAgICAgICAgICAvLyBvdXQgYW5kIG91dHNpemUgc2FvIDAgcG9ycXVlIGFpbmRhIG5hbyBzYWJlbW9zIG8gdGFtYW5oby4KCiAgICAgICAgICAgIC8vIGRlbGVnYXRlY2FsbChnLCBhLCBpbiwgaW5zaXplLCBvdXQsIG91dHNpemUpIC0KICAgICAgICAgICAgLy8gLSBjb250cmF0byBkZSBjaGFtYWRhIG5vIGVuZGVyZWNvIGEKICAgICAgICAgICAgLy8gLSBjb20gZW50cmFkYSBtZW1baW4/KGluK2luc2l6ZSkpCiAgICAgICAgICAgIC8vIC0gZm9ybmVjaW1lbnRvIGRlIGdhcyBnCiAgICAgICAgICAgIC8vIC0gYXJlYSBkZSBzYWlkYSBtZW1bb3V0PyhvdXQrb3V0c2l6ZSkpCiAgICAgICAgICAgIC8vIC0gcmV0b3JuYW5kbyAwIGVtIGNhc28gZGUgZXJybyAocG9yIGV4ZW1wbG8sIGZhbHRhIGRlIGdhcykgZSAxIGVtIGNhc28gZGUgc3VjZXNzbwogICAgICAgICAgICBsZXQgcmVzdWx0IDo9IGRlbGVnYXRlY2FsbChnYXMoKSwgX2ltcGxlbWVudGF0aW9uLCAwLCBjYWxsZGF0YXNpemUoKSwgMCwgMCkKCiAgICAgICAgICAgIC8vIENvcGllIG9zIGRhZG9zIHJldG9ybmFkb3MuCiAgICAgICAgICAgIC8vIHJldHVybmRhdGFjb3B5KHQsIGYsIHMpIC0gY29waWEgUyBieXRlcyBkZSByZXR1cm5kYXRhIG5hIHBvc2ljYW8gZiBwYXJhIG1lbSBuYSBwb3NpY2FvIHQKICAgICAgICAgICAgLy8gcmV0dXJuZGF0YXNpemUoKSAtIHRhbWFuaG8gZG8gdWx0aW1vIHJldHVybmRhdGEKICAgICAgICAgICAgcmV0dXJuZGF0YWNvcHkoMCwgMCwgcmV0dXJuZGF0YXNpemUoKSkKCiAgICAgICAgICAgIHN3aXRjaCByZXN1bHQKICAgICAgICAgICAgLy8gZGVsZWdhdGVjYWxsIHJldG9ybmEgMCBlbSBjYXNvIGRlIGVycm8uCiAgICAgICAgICAgIGNhc2UgMCB7CiAgICAgICAgICAgICAgICAvLyByZXZlcnQocCwgcykgLSBmaW5hbGl6YSBhIGV4ZWN1Y2FvLCByZXZlcnRlIG11ZGFuY2FzIGRlIGVzdGFkbywgcmV0b3JuYSBkYWRvcyBtZW1bcD8ocCtzKSkKICAgICAgICAgICAgICAgIHJldmVydCgwLCByZXR1cm5kYXRhc2l6ZSgpKQogICAgICAgICAgICB9CiAgICAgICAgICAgIGRlZmF1bHQgewogICAgICAgICAgICAgICAgLy8gcmV0dXJuKHAsIHMpIC0gZmluYWxpemEgYSBleGVjdWNhbywgcmV0b3JuYSBkYWRvcyBtZW1bcD8ocCtzKSkKICAgICAgICAgICAgICAgIHJldHVybigwLCByZXR1cm5kYXRhc2l6ZSgpKQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGZ1bmN0aW9uIF9mYWxsYmFjaygpIHByaXZhdGUgewogICAgICAgIF9kZWxlZ2F0ZShfZ2V0SW1wbGVtZW50YXRpb24oKSk7CiAgICB9CgogICAgZmFsbGJhY2soKSBleHRlcm5hbCBwYXlhYmxlIHsKICAgICAgICBfZmFsbGJhY2soKTsKICAgIH0KCiAgICByZWNlaXZlKCkgZXh0ZXJuYWwgcGF5YWJsZSB7CiAgICAgICAgX2ZhbGxiYWNrKCk7CiAgICB9Cn0KCmNvbnRyYWN0IFByb3h5QWRtaW4gewogICAgYWRkcmVzcyBwdWJsaWMgb3duZXI7CgogICAgY29uc3RydWN0b3IoKSB7CiAgICAgICAgb3duZXIgPSBtc2cuc2VuZGVyOwogICAgfQoKICAgIG1vZGlmaWVyIG9ubHlPd25lcigpIHsKICAgICAgICByZXF1aXJlKG1zZy5zZW5kZXIgPT0gb3duZXIsICJub3Qgb3duZXIiKTsKICAgICAgICBfOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldFByb3h5QWRtaW4oYWRkcmVzcyBwcm94eSkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChhZGRyZXNzKSB7CiAgICAgICAgKGJvb2wgb2ssIGJ5dGVzIG1lbW9yeSByZXMpID0gcHJveHkuc3RhdGljY2FsbCgKICAgICAgICAgICAgYWJpLmVuY29kZUNhbGwoUHJveHkuaW1wbGVtZW50YXRpb24sICgpKQogICAgICAgICk7CiAgICAgICAgcmVxdWlyZShvaywgImNhbGwgZmFpbGVkIik7CiAgICAgICAgcmV0dXJuIGFiaS5kZWNvZGUocmVzLCAoYWRkcmVzcykpOwogICAgfQoKICAgIGZ1bmN0aW9uIGdldFByb3h5SW1wbGVtZW50YXRpb24oYWRkcmVzcyBwcm94eSkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChhZGRyZXNzKSB7CiAgICAgICAgKGJvb2wgb2ssIGJ5dGVzIG1lbW9yeSByZXMpID0gcHJveHkuc3RhdGljY2FsbChhYmkuZW5jb2RlQ2FsbChQcm94eS5hZG1pbiwgKCkpKTsKICAgICAgICByZXF1aXJlKG9rLCAiY2FsbCBmYWlsZWQiKTsKICAgICAgICByZXR1cm4gYWJpLmRlY29kZShyZXMsIChhZGRyZXNzKSk7CiAgICB9CgogICAgZnVuY3Rpb24gY2hhbmdlUHJveHlBZG1pbihhZGRyZXNzIHBheWFibGUgcHJveHksIGFkZHJlc3MgYWRtaW4pIGV4dGVybmFsIG9ubHlPd25lciB7CiAgICAgICAgUHJveHkocHJveHkpLmNoYW5nZUFkbWluKGFkbWluKTsKICAgIH0KCiAgICBmdW5jdGlvbiB1cGdyYWRlKGFkZHJlc3MgcGF5YWJsZSBwcm94eSwgYWRkcmVzcyBpbXBsZW1lbnRhdGlvbikgZXh0ZXJuYWwgb25seU93bmVyIHsKICAgICAgICBQcm94eShwcm94eSkudXBncmFkZVRvKGltcGxlbWVudGF0aW9uKTsKICAgIH0KfQoKbGlicmFyeSBTdG9yYWdlU2xvdCB7CiAgICBzdHJ1Y3QgQWRkcmVzc1Nsb3QgewogICAgICAgIGFkZHJlc3MgdmFsdWU7CiAgICB9CgogICAgZnVuY3Rpb24gZ2V0QWRkcmVzc1Nsb3QoYnl0ZXMzMiBzbG90KQogICAgICAgIGludGVybmFsCiAgICAgICAgcHVyZQogICAgICAgIHJldHVybnMgKEFkZHJlc3NTbG90IHN0b3JhZ2UgcikKICAgIHsKICAgICAgICBhc3NlbWJseSB7CiAgICAgICAgICAgIHIuc2xvdCA6PSBzbG90CiAgICAgICAgfQogICAgfQp9Cgpjb250cmFjdCBUZXN0U2xvdCB7CiAgICBieXRlczMyIHB1YmxpYyBjb25zdGFudCBzbG90ID0ga2VjY2FrMjU2KCJURVNUX1NMT1QiKTsKCiAgICBmdW5jdGlvbiBnZXRTbG90KCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChhZGRyZXNzKSB7CiAgICAgICAgcmV0dXJuIFN0b3JhZ2VTbG90LmdldEFkZHJlc3NTbG90KHNsb3QpLnZhbHVlOwogICAgfQoKICAgIGZ1bmN0aW9uIHdyaXRlU2xvdChhZGRyZXNzIF9hZGRyKSBleHRlcm5hbCB7CiAgICAgICAgU3RvcmFnZVNsb3QuZ2V0QWRkcmVzc1Nsb3Qoc2xvdCkudmFsdWUgPSBfYWRkcjsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/transferencia-de-token-sem-gas.md b/src/exemplos/aplicacoes/transferencia-de-token-sem-gas.md
new file mode 100644
index 0000000..82af838
--- /dev/null
+++ b/src/exemplos/aplicacoes/transferencia-de-token-sem-gas.md
@@ -0,0 +1,309 @@
+# Transferência de token sem gás
+
+Transferência de tokens ERC20 sem gás com transação Meta
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+interface IERC20Permit {
+ function totalSupply() external view returns (uint256);
+
+ function balanceOf(address account) external view returns (uint256);
+
+ function transfer(address recipient, uint256 amount) external returns (bool);
+
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ function transferFrom(
+ address sender,
+ address recipient,
+ uint256 amount
+ ) external returns (bool);
+
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external;
+
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+contract GaslessTokenTransfer {
+ function send(
+ address token,
+ address sender,
+ address receiver,
+ uint256 amount,
+ uint256 fee,
+ uint256 deadline,
+ // Assinatura da autorização
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external {
+ // Autorização
+ IERC20Permit(token).permit(
+ sender,
+ address(this),
+ amount + fee,
+ deadline,
+ v,
+ r,
+ s
+ );
+ // Enviar o valor ao destinatário
+ IERC20Permit(token).transferFrom(sender, receiver, amount);
+ // Aceitar taxa - enviar taxa para msg.sender
+ IERC20Permit(token).transferFrom(sender, msg.sender, fee);
+ }
+}
+```
+
+Exemplo de `ERC20` que implementa a autorização copiada do solmate
+
+```solidity
+// SPDX-License-Identifier: AGPL-3.0-only
+pragma solidity >=0.8.0;
+
+/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
+/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
+/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
+/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
+abstract contract ERC20 {
+ /*//////////////////////////////////////////////////////////////
+ EVENTS
+ //////////////////////////////////////////////////////////////*/
+
+ event Transfer(address indexed from, address indexed to, uint256 amount);
+
+ event Approval(address indexed owner, address indexed spender, uint256 amount);
+
+ /*//////////////////////////////////////////////////////////////
+ METADATA STORAGE
+ //////////////////////////////////////////////////////////////*/
+
+ string public name;
+
+ string public symbol;
+
+ uint8 public immutable decimals;
+
+ /*//////////////////////////////////////////////////////////////
+ ERC20 STORAGE
+ //////////////////////////////////////////////////////////////*/
+
+ uint256 public totalSupply;
+
+ mapping(address => uint256) public balanceOf;
+
+ mapping(address => mapping(address => uint256)) public allowance;
+
+ /*//////////////////////////////////////////////////////////////
+ EIP-2612 STORAGE
+ //////////////////////////////////////////////////////////////*/
+
+ uint256 internal immutable INITIAL_CHAIN_ID;
+
+ bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
+
+ mapping(address => uint256) public nonces;
+
+ /*//////////////////////////////////////////////////////////////
+ CONSTRUCTOR
+ //////////////////////////////////////////////////////////////*/
+
+ constructor(string memory _name, string memory _symbol, uint8 _decimals) {
+ name = _name;
+ symbol = _symbol;
+ decimals = _decimals;
+
+ INITIAL_CHAIN_ID = block.chainid;
+ INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ ERC20 LOGIC
+ //////////////////////////////////////////////////////////////*/
+
+ function approve(address spender, uint256 amount) public virtual returns (bool) {
+ allowance[msg.sender][spender] = amount;
+
+ emit Approval(msg.sender, spender, amount);
+
+ return true;
+ }
+
+ function transfer(address to, uint256 amount) public virtual returns (bool) {
+ balanceOf[msg.sender] -= amount;
+
+ // Não pode ultrapassar o limite porque a soma de todos os usuários
+ // Não pode exceder o valor máximo de uint256.
+ unchecked {
+ balanceOf[to] += amount;
+ }
+
+ emit Transfer(msg.sender, to, amount);
+
+ return true;
+ }
+
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ ) public virtual returns (bool) {
+ uint256 allowed = allowance[from][msg.sender]; // Poupa gás para aprovações limitadas.
+
+ if (allowed != type(uint256).max)
+ allowance[from][msg.sender] = allowed - amount;
+
+ balanceOf[from] -= amount;
+
+ // Não pode ultrapassar o limite porque a soma de todos os usuários
+ // Não pode exceder o valor máximo de uint256.
+ unchecked {
+ balanceOf[to] += amount;
+ }
+
+ emit Transfer(from, to, amount);
+
+ return true;
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ EIP-2612 LOGIC
+ //////////////////////////////////////////////////////////////*/
+
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) public virtual {
+ require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
+
+ // Unchecked because the only math done is incrementing
+ // the owner's nonce which cannot realistically overflow.
+
+ // Não verificado porque a única matemática feita é o incremento do
+ // o nonce do proprietário, que não pode realisticamente ultrapassar.
+ unchecked {
+ address recoveredAddress = ecrecover(
+ keccak256(
+ abi.encodePacked(
+ "\x19\x01",
+ DOMAIN_SEPARATOR(),
+ keccak256(
+ abi.encode(
+ keccak256(
+ "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
+ ),
+ owner,
+ spender,
+ value,
+ nonces[owner]++,
+ deadline
+ )
+ )
+ )
+ ),
+ v,
+ r,
+ s
+ );
+
+ require(
+ recoveredAddress != address(0) && recoveredAddress == owner,
+ "INVALID_SIGNER"
+ );
+
+ allowance[recoveredAddress][spender] = value;
+ }
+
+ emit Approval(owner, spender, value);
+ }
+
+ function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
+ return
+ block.chainid == INITIAL_CHAIN_ID
+ ? INITIAL_DOMAIN_SEPARATOR
+ : computeDomainSeparator();
+ }
+
+ function computeDomainSeparator() internal view virtual returns (bytes32) {
+ return
+ keccak256(
+ abi.encode(
+ keccak256(
+ "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
+ ),
+ keccak256(bytes(name)),
+ keccak256("1"),
+ block.chainid,
+ address(this)
+ )
+ );
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ INTERNAL MINT/BURN LOGIC
+ //////////////////////////////////////////////////////////////*/
+
+ function _mint(address to, uint256 amount) internal virtual {
+ totalSupply += amount;
+
+ // Não pode ultrapassar o limite porque a soma de todos os usuários
+ // Não pode exceder o valor máximo de uint256.
+ unchecked {
+ balanceOf[to] += amount;
+ }
+
+ emit Transfer(address(0), to, amount);
+ }
+
+ function _burn(address from, uint256 amount) internal virtual {
+ balanceOf[from] -= amount;
+
+ // Cannot underflow because a user's balance
+ // will never be larger than the total supply.
+
+ // Não é possível underflow porque o saldo do usuário
+ // nunca será maior do que o suprimento total.
+ unchecked {
+ totalSupply -= amount;
+ }
+
+ emit Transfer(from, address(0), amount);
+ }
+}
+
+contract ERC20Permit is ERC20 {
+ constructor(
+ string memory _name,
+ string memory _symbol,
+ uint8 _decimals
+ ) ERC20(_name, _symbol, _decimals) {}
+
+ function mint(address to, uint256 amount) public {
+ _mint(to, amount);
+ }
+}
+```
+
+## Teste no Remix
+
+- [ERC20Permit.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmludGVyZmFjZSBJRVJDMjBQZXJtaXQgewogICAgZnVuY3Rpb24gdG90YWxTdXBwbHkoKSBleHRlcm5hbCB2aWV3IHJldHVybnMgKHVpbnQyNTYpOwoKICAgIGZ1bmN0aW9uIGJhbGFuY2VPZihhZGRyZXNzIGFjY291bnQpIGV4dGVybmFsIHZpZXcgcmV0dXJucyAodWludDI1Nik7CgogICAgZnVuY3Rpb24gdHJhbnNmZXIoYWRkcmVzcyByZWNpcGllbnQsIHVpbnQyNTYgYW1vdW50KSBleHRlcm5hbCByZXR1cm5zIChib29sKTsKCiAgICBmdW5jdGlvbiBhbGxvd2FuY2UoYWRkcmVzcyBvd25lciwgYWRkcmVzcyBzcGVuZGVyKSBleHRlcm5hbCB2aWV3IHJldHVybnMgKHVpbnQyNTYpOwoKICAgIGZ1bmN0aW9uIGFwcHJvdmUoYWRkcmVzcyBzcGVuZGVyLCB1aW50MjU2IGFtb3VudCkgZXh0ZXJuYWwgcmV0dXJucyAoYm9vbCk7CgogICAgZnVuY3Rpb24gdHJhbnNmZXJGcm9tKAogICAgICAgIGFkZHJlc3Mgc2VuZGVyLAogICAgICAgIGFkZHJlc3MgcmVjaXBpZW50LAogICAgICAgIHVpbnQyNTYgYW1vdW50CiAgICApIGV4dGVybmFsIHJldHVybnMgKGJvb2wpOwoKICAgIGZ1bmN0aW9uIHBlcm1pdCgKICAgICAgICBhZGRyZXNzIG93bmVyLAogICAgICAgIGFkZHJlc3Mgc3BlbmRlciwKICAgICAgICB1aW50MjU2IHZhbHVlLAogICAgICAgIHVpbnQyNTYgZGVhZGxpbmUsCiAgICAgICAgdWludDggdiwKICAgICAgICBieXRlczMyIHIsCiAgICAgICAgYnl0ZXMzMiBzCiAgICApIGV4dGVybmFsOwoKICAgIGV2ZW50IFRyYW5zZmVyKGFkZHJlc3MgaW5kZXhlZCBmcm9tLCBhZGRyZXNzIGluZGV4ZWQgdG8sIHVpbnQyNTYgdmFsdWUpOwogICAgZXZlbnQgQXBwcm92YWwoYWRkcmVzcyBpbmRleGVkIG93bmVyLCBhZGRyZXNzIGluZGV4ZWQgc3BlbmRlciwgdWludDI1NiB2YWx1ZSk7Cn0KCmNvbnRyYWN0IEdhc2xlc3NUb2tlblRyYW5zZmVyIHsKICAgIGZ1bmN0aW9uIHNlbmQoCiAgICAgICAgYWRkcmVzcyB0b2tlbiwKICAgICAgICBhZGRyZXNzIHNlbmRlciwKICAgICAgICBhZGRyZXNzIHJlY2VpdmVyLAogICAgICAgIHVpbnQyNTYgYW1vdW50LAogICAgICAgIHVpbnQyNTYgZmVlLAogICAgICAgIHVpbnQyNTYgZGVhZGxpbmUsCiAgICAgICAgLy8gQXNzaW5hdHVyYSBkYSBhdXRvcml6YWNhbwogICAgICAgIHVpbnQ4IHYsCiAgICAgICAgYnl0ZXMzMiByLAogICAgICAgIGJ5dGVzMzIgcwogICAgKSBleHRlcm5hbCB7CiAgICAgICAgLy8gQXV0b3JpemFjYW8KICAgICAgICBJRVJDMjBQZXJtaXQodG9rZW4pLnBlcm1pdCgKICAgICAgICAgICAgc2VuZGVyLAogICAgICAgICAgICBhZGRyZXNzKHRoaXMpLAogICAgICAgICAgICBhbW91bnQgKyBmZWUsCiAgICAgICAgICAgIGRlYWRsaW5lLAogICAgICAgICAgICB2LAogICAgICAgICAgICByLAogICAgICAgICAgICBzCiAgICAgICAgKTsKICAgICAgICAvLyBFbnZpYXIgbyB2YWxvciBhbyBkZXN0aW5hdGFyaW8KICAgICAgICBJRVJDMjBQZXJtaXQodG9rZW4pLnRyYW5zZmVyRnJvbShzZW5kZXIsIHJlY2VpdmVyLCBhbW91bnQpOwogICAgICAgIC8vIEFjZWl0YXIgdGF4YSAtIGVudmlhciB0YXhhIHBhcmEgbXNnLnNlbmRlcgogICAgICAgIElFUkMyMFBlcm1pdCh0b2tlbikudHJhbnNmZXJGcm9tKHNlbmRlciwgbXNnLnNlbmRlciwgZmVlKTsKICAgIH0KfQ=&version=soljson-v0.8.20+commit.a1b79de6.js)
+
+- [GaslessTokenTransfer.sol](https://remix.ethereum.org/#codeLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkKcHJhZ21hIHNvbGlkaXR5ID49MC44LjA7CgovLy8gQG5vdGljZSBNb2Rlcm4gYW5kIGdhcyBlZmZpY2llbnQgRVJDMjAgKyBFSVAtMjYxMiBpbXBsZW1lbnRhdGlvbi4KLy8vIEBhdXRob3IgU29sbWF0ZSAoaHR0cHM6Ly9naXRodWIuY29tL3RyYW5zbWlzc2lvbnMxMS9zb2xtYXRlL2Jsb2IvbWFpbi9zcmMvdG9rZW5zL0VSQzIwLnNvbCkKLy8vIEBhdXRob3IgTW9kaWZpZWQgZnJvbSBVbmlzd2FwIChodHRwczovL2dpdGh1Yi5jb20vVW5pc3dhcC91bmlzd2FwLXYyLWNvcmUvYmxvYi9tYXN0ZXIvY29udHJhY3RzL1VuaXN3YXBWMkVSQzIwLnNvbCkKLy8vIEBkZXYgRG8gbm90IG1hbnVhbGx5IHNldCBiYWxhbmNlcyB3aXRob3V0IHVwZGF0aW5nIHRvdGFsU3VwcGx5LCBhcyB0aGUgc3VtIG9mIGFsbCB1c2VyIGJhbGFuY2VzIG11c3Qgbm90IGV4Y2VlZCBpdC4KYWJzdHJhY3QgY29udHJhY3QgRVJDMjAgewogICAgLyovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFVkVOVFMKICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vKi8KCiAgICBldmVudCBUcmFuc2ZlcihhZGRyZXNzIGluZGV4ZWQgZnJvbSwgYWRkcmVzcyBpbmRleGVkIHRvLCB1aW50MjU2IGFtb3VudCk7CgogICAgZXZlbnQgQXBwcm92YWwoYWRkcmVzcyBpbmRleGVkIG93bmVyLCBhZGRyZXNzIGluZGV4ZWQgc3BlbmRlciwgdWludDI1NiBhbW91bnQpOwoKICAgIC8qLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1FVEFEQVRBIFNUT1JBR0UKICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vKi8KCiAgICBzdHJpbmcgcHVibGljIG5hbWU7CgogICAgc3RyaW5nIHB1YmxpYyBzeW1ib2w7CgogICAgdWludDggcHVibGljIGltbXV0YWJsZSBkZWNpbWFsczsKCiAgICAvKi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVSQzIwIFNUT1JBR0UKICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vKi8KCiAgICB1aW50MjU2IHB1YmxpYyB0b3RhbFN1cHBseTsKCiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gdWludDI1NikgcHVibGljIGJhbGFuY2VPZjsKCiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTYpKSBwdWJsaWMgYWxsb3dhbmNlOwoKICAgIC8qLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVJUC0yNjEyIFNUT1JBR0UKICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vKi8KCiAgICB1aW50MjU2IGludGVybmFsIGltbXV0YWJsZSBJTklUSUFMX0NIQUlOX0lEOwoKICAgIGJ5dGVzMzIgaW50ZXJuYWwgaW1tdXRhYmxlIElOSVRJQUxfRE9NQUlOX1NFUEFSQVRPUjsKCiAgICBtYXBwaW5nKGFkZHJlc3MgPT4gdWludDI1NikgcHVibGljIG5vbmNlczsKCiAgICAvKi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDT05TVFJVQ1RPUgogICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8qLwoKICAgIGNvbnN0cnVjdG9yKHN0cmluZyBtZW1vcnkgX25hbWUsIHN0cmluZyBtZW1vcnkgX3N5bWJvbCwgdWludDggX2RlY2ltYWxzKSB7CiAgICAgICAgbmFtZSA9IF9uYW1lOwogICAgICAgIHN5bWJvbCA9IF9zeW1ib2w7CiAgICAgICAgZGVjaW1hbHMgPSBfZGVjaW1hbHM7CgogICAgICAgIElOSVRJQUxfQ0hBSU5fSUQgPSBibG9jay5jaGFpbmlkOwogICAgICAgIElOSVRJQUxfRE9NQUlOX1NFUEFSQVRPUiA9IGNvbXB1dGVEb21haW5TZXBhcmF0b3IoKTsKICAgIH0KCiAgICAvKi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFUkMyMCBMT0dJQwogICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8qLwoKICAgIGZ1bmN0aW9uIGFwcHJvdmUoYWRkcmVzcyBzcGVuZGVyLCB1aW50MjU2IGFtb3VudCkgcHVibGljIHZpcnR1YWwgcmV0dXJucyAoYm9vbCkgewogICAgICAgIGFsbG93YW5jZVttc2cuc2VuZGVyXVtzcGVuZGVyXSA9IGFtb3VudDsKCiAgICAgICAgZW1pdCBBcHByb3ZhbChtc2cuc2VuZGVyLCBzcGVuZGVyLCBhbW91bnQpOwoKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBmdW5jdGlvbiB0cmFuc2ZlcihhZGRyZXNzIHRvLCB1aW50MjU2IGFtb3VudCkgcHVibGljIHZpcnR1YWwgcmV0dXJucyAoYm9vbCkgewogICAgICAgIGJhbGFuY2VPZlttc2cuc2VuZGVyXSAtPSBhbW91bnQ7CgogICAgICAgIC8vIE7Do28gcG9kZSB1bHRyYXBhc3NhciBvIGxpbWl0ZSBwb3JxdWUgYSBzb21hIGRlIHRvZG9zIG9zIHVzdcOhcmlvcwogICAgICAgIC8vIE7Do28gcG9kZSBleGNlZGVyIG8gdmFsb3IgbcOheGltbyBkZSB1aW50MjU2LgogICAgICAgIHVuY2hlY2tlZCB7CiAgICAgICAgICAgIGJhbGFuY2VPZlt0b10gKz0gYW1vdW50OwogICAgICAgIH0KCiAgICAgICAgZW1pdCBUcmFuc2Zlcihtc2cuc2VuZGVyLCB0bywgYW1vdW50KTsKCiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgZnVuY3Rpb24gdHJhbnNmZXJGcm9tKAogICAgICAgIGFkZHJlc3MgZnJvbSwKICAgICAgICBhZGRyZXNzIHRvLAogICAgICAgIHVpbnQyNTYgYW1vdW50CiAgICApIHB1YmxpYyB2aXJ0dWFsIHJldHVybnMgKGJvb2wpIHsKICAgICAgICB1aW50MjU2IGFsbG93ZWQgPSBhbGxvd2FuY2VbZnJvbV1bbXNnLnNlbmRlcl07IC8vIFBvdXBhIGfDoXMgcGFyYSBhcHJvdmHDp8O1ZXMgbGltaXRhZGFzLgoKICAgICAgICBpZiAoYWxsb3dlZCAhPSB0eXBlKHVpbnQyNTYpLm1heCkKICAgICAgICAgICAgYWxsb3dhbmNlW2Zyb21dW21zZy5zZW5kZXJdID0gYWxsb3dlZCAtIGFtb3VudDsKCiAgICAgICAgYmFsYW5jZU9mW2Zyb21dIC09IGFtb3VudDsKCiAgICAgICAvLyBOw6NvIHBvZGUgdWx0cmFwYXNzYXIgbyBsaW1pdGUgcG9ycXVlIGEgc29tYSBkZSB0b2RvcyBvcyB1c3XDoXJpb3MKICAgICAgIC8vIE7Do28gcG9kZSBleGNlZGVyIG8gdmFsb3IgbcOheGltbyBkZSB1aW50MjU2LgogICAgICAgIHVuY2hlY2tlZCB7CiAgICAgICAgICAgIGJhbGFuY2VPZlt0b10gKz0gYW1vdW50OwogICAgICAgIH0KCiAgICAgICAgZW1pdCBUcmFuc2Zlcihmcm9tLCB0bywgYW1vdW50KTsKCiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgLyovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVJUC0yNjEyIExPR0lDCiAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLyovCgogICAgZnVuY3Rpb24gcGVybWl0KAogICAgICAgIGFkZHJlc3Mgb3duZXIsCiAgICAgICAgYWRkcmVzcyBzcGVuZGVyLAogICAgICAgIHVpbnQyNTYgdmFsdWUsCiAgICAgICAgdWludDI1NiBkZWFkbGluZSwKICAgICAgICB1aW50OCB2LAogICAgICAgIGJ5dGVzMzIgciwKICAgICAgICBieXRlczMyIHMKICAgICkgcHVibGljIHZpcnR1YWwgewogICAgICAgIHJlcXVpcmUoZGVhZGxpbmUgPj0gYmxvY2sudGltZXN0YW1wLCAiUEVSTUlUX0RFQURMSU5FX0VYUElSRUQiKTsKCiAgICAgICAgLy8gVW5jaGVja2VkIGJlY2F1c2UgdGhlIG9ubHkgbWF0aCBkb25lIGlzIGluY3JlbWVudGluZwogICAgICAgIC8vIHRoZSBvd25lcidzIG5vbmNlIHdoaWNoIGNhbm5vdCByZWFsaXN0aWNhbGx5IG92ZXJmbG93LgoKICAgICAgICAvLyBOw6NvIHZlcmlmaWNhZG8gcG9ycXVlIGEgw7puaWNhIG1hdGVtw6F0aWNhIGZlaXRhIMOpIG8gaW5jcmVtZW50byBkbwogICAgICAgIC8vIG8gbm9uY2UgZG8gcHJvcHJpZXTDoXJpbywgcXVlIG7Do28gcG9kZSByZWFsaXN0aWNhbWVudGUgdWx0cmFwYXNzYXIuCiAgICAgICAgdW5jaGVja2VkIHsKICAgICAgICAgICAgYWRkcmVzcyByZWNvdmVyZWRBZGRyZXNzID0gZWNyZWNvdmVyKAogICAgICAgICAgICAgICAga2VjY2FrMjU2KAogICAgICAgICAgICAgICAgICAgIGFiaS5lbmNvZGVQYWNrZWQoCiAgICAgICAgICAgICAgICAgICAgICAgICJceDE5XHgwMSIsCiAgICAgICAgICAgICAgICAgICAgICAgIERPTUFJTl9TRVBBUkFUT1IoKSwKICAgICAgICAgICAgICAgICAgICAgICAga2VjY2FrMjU2KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWJpLmVuY29kZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWNjYWsyNTYoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQZXJtaXQoYWRkcmVzcyBvd25lcixhZGRyZXNzIHNwZW5kZXIsdWludDI1NiB2YWx1ZSx1aW50MjU2IG5vbmNlLHVpbnQyNTYgZGVhZGxpbmUpIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3duZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlbmRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25jZXNbb3duZXJdKyssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhZGxpbmUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICB2LAogICAgICAgICAgICAgICAgciwKICAgICAgICAgICAgICAgIHMKICAgICAgICAgICAgKTsKCiAgICAgICAgICAgIHJlcXVpcmUoCiAgICAgICAgICAgICAgICByZWNvdmVyZWRBZGRyZXNzICE9IGFkZHJlc3MoMCkgJiYgcmVjb3ZlcmVkQWRkcmVzcyA9PSBvd25lciwKICAgICAgICAgICAgICAgICJJTlZBTElEX1NJR05FUiIKICAgICAgICAgICAgKTsKCiAgICAgICAgICAgIGFsbG93YW5jZVtyZWNvdmVyZWRBZGRyZXNzXVtzcGVuZGVyXSA9IHZhbHVlOwogICAgICAgIH0KCiAgICAgICAgZW1pdCBBcHByb3ZhbChvd25lciwgc3BlbmRlciwgdmFsdWUpOwogICAgfQoKICAgIGZ1bmN0aW9uIERPTUFJTl9TRVBBUkFUT1IoKSBwdWJsaWMgdmlldyB2aXJ0dWFsIHJldHVybnMgKGJ5dGVzMzIpIHsKICAgICAgICByZXR1cm4KICAgICAgICAgICAgYmxvY2suY2hhaW5pZCA9PSBJTklUSUFMX0NIQUlOX0lECiAgICAgICAgICAgICAgICA/IElOSVRJQUxfRE9NQUlOX1NFUEFSQVRPUgogICAgICAgICAgICAgICAgOiBjb21wdXRlRG9tYWluU2VwYXJhdG9yKCk7CiAgICB9CgogICAgZnVuY3Rpb24gY29tcHV0ZURvbWFpblNlcGFyYXRvcigpIGludGVybmFsIHZpZXcgdmlydHVhbCByZXR1cm5zIChieXRlczMyKSB7CiAgICAgICAgcmV0dXJuCiAgICAgICAgICAgIGtlY2NhazI1NigKICAgICAgICAgICAgICAgIGFiaS5lbmNvZGUoCiAgICAgICAgICAgICAgICAgICAga2VjY2FrMjU2KAogICAgICAgICAgICAgICAgICAgICAgICAiRUlQNzEyRG9tYWluKHN0cmluZyBuYW1lLHN0cmluZyB2ZXJzaW9uLHVpbnQyNTYgY2hhaW5JZCxhZGRyZXNzIHZlcmlmeWluZ0NvbnRyYWN0KSIKICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgIGtlY2NhazI1NihieXRlcyhuYW1lKSksCiAgICAgICAgICAgICAgICAgICAga2VjY2FrMjU2KCIxIiksCiAgICAgICAgICAgICAgICAgICAgYmxvY2suY2hhaW5pZCwKICAgICAgICAgICAgICAgICAgICBhZGRyZXNzKHRoaXMpCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICk7CiAgICB9CgogICAgLyovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgICAgICAgICAgICAgICAgICAgICBJTlRFUk5BTCBNSU5UL0JVUk4gTE9HSUMKICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vKi8KCiAgICBmdW5jdGlvbiBfbWludChhZGRyZXNzIHRvLCB1aW50MjU2IGFtb3VudCkgaW50ZXJuYWwgdmlydHVhbCB7CiAgICAgICAgdG90YWxTdXBwbHkgKz0gYW1vdW50OwoKICAgICAgICAvLyBOw6NvIHBvZGUgdWx0cmFwYXNzYXIgbyBsaW1pdGUgcG9ycXVlIGEgc29tYSBkZSB0b2RvcyBvcyB1c3XDoXJpb3MKICAgICAgICAvLyBOw6NvIHBvZGUgZXhjZWRlciBvIHZhbG9yIG3DoXhpbW8gZGUgdWludDI1Ni4KICAgICAgICB1bmNoZWNrZWQgewogICAgICAgICAgICBiYWxhbmNlT2ZbdG9dICs9IGFtb3VudDsKICAgICAgICB9CgogICAgICAgIGVtaXQgVHJhbnNmZXIoYWRkcmVzcygwKSwgdG8sIGFtb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gX2J1cm4oYWRkcmVzcyBmcm9tLCB1aW50MjU2IGFtb3VudCkgaW50ZXJuYWwgdmlydHVhbCB7CiAgICAgICAgYmFsYW5jZU9mW2Zyb21dIC09IGFtb3VudDsKCiAgICAgICAgLy8gQ2Fubm90IHVuZGVyZmxvdyBiZWNhdXNlIGEgdXNlcidzIGJhbGFuY2UKICAgICAgICAvLyB3aWxsIG5ldmVyIGJlIGxhcmdlciB0aGFuIHRoZSB0b3RhbCBzdXBwbHkuCgogICAgICAgIC8vIE7Do28gw6kgcG9zc8OtdmVsIHVuZGVyZmxvdyBwb3JxdWUgbyBzYWxkbyBkbyB1c3XDoXJpbwogICAgICAgIC8vIG51bmNhIHNlcsOhIG1haW9yIGRvIHF1ZSBvIHN1cHJpbWVudG8gdG90YWwuCiAgICAgICAgdW5jaGVja2VkIHsKICAgICAgICAgICAgdG90YWxTdXBwbHkgLT0gYW1vdW50OwogICAgICAgIH0KCiAgICAgICAgZW1pdCBUcmFuc2Zlcihmcm9tLCBhZGRyZXNzKDApLCBhbW91bnQpOwogICAgfQp9Cgpjb250cmFjdCBFUkMyMFBlcm1pdCBpcyBFUkMyMCB7CiAgICBjb25zdHJ1Y3RvcigKICAgICAgICBzdHJpbmcgbWVtb3J5IF9uYW1lLAogICAgICAgIHN0cmluZyBtZW1vcnkgX3N5bWJvbCwKICAgICAgICB1aW50OCBfZGVjaW1hbHMKICAgICkgRVJDMjAoX25hbWUsIF9zeW1ib2wsIF9kZWNpbWFscykge30KCiAgICBmdW5jdGlvbiBtaW50KGFkZHJlc3MgdG8sIHVpbnQyNTYgYW1vdW50KSBwdWJsaWMgewogICAgICAgIF9taW50KHRvLCBhbW91bnQpOwogICAgfQp9=&version=soljson-v0.8.20+commit.a1b79de6.js)
diff --git a/src/exemplos/aplicacoes/vaquinha.md b/src/exemplos/aplicacoes/vaquinha.md
new file mode 100644
index 0000000..e307b71
--- /dev/null
+++ b/src/exemplos/aplicacoes/vaquinha.md
@@ -0,0 +1,149 @@
+# Vaquinha
+
+Token ERC20 de financiamento coletivo
+
+1. O usuário cria uma campanha.
+2. Os usuários podem se comprometer, transferindo seu token para uma campanha.
+3. Após o término da campanha, o criador da campanha pode reivindicar os fundos se o valor total prometido for maior que a meta da campanha.
+4. Caso contrário, a campanha não atingiu seu objetivo, os usuários podem retirar sua promessa.
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.20;
+
+interface IERC20 {
+ function transfer(address, uint) external returns (bool);
+
+ function transferFrom(
+ address,
+ address,
+ uint
+ ) external returns (bool);
+}
+
+contract CrowdFund {
+ event Launch(
+ uint id,
+ address indexed creator,
+ uint goal,
+ uint32 startAt,
+ uint32 endAt
+ );
+ event Cancel(uint id);
+ event Pledge(uint indexed id, address indexed caller, uint amount);
+ event Unpledge(uint indexed id, address indexed caller, uint amount);
+ event Claim(uint id);
+ event Refund(uint id, address indexed caller, uint amount);
+
+ struct Campaign {
+ // Criador da campanha
+ address creator;
+ // Quantidade de tokens para arrecadar
+ uint goal;
+ // Valor total prometido
+ uint pledged;
+ // Timestamp do início da campanha
+ uint32 startAt;
+ // Timestamp do final da campanha
+ uint32 endAt;
+ // True se a meta foi alcançada e o criador reivindicou os tokens.
+ bool claimed;
+ }
+
+ IERC20 public immutable token;
+ // Contagem total de campanhas criadas.
+ // Também é usado para gerar id para novas campanhas.
+ uint public count;
+ // Mapping do id para o Campaign
+ mapping(uint => Campaign) public campaigns;
+ // Mapping do campaign id => doador => valor prometido
+ mapping(uint => mapping(address => uint)) public pledgedAmount;
+
+ constructor(address _token) {
+ token = IERC20(_token);
+ }
+
+ function launch(
+ uint _goal,
+ uint32 _startAt,
+ uint32 _endAt
+ ) external {
+ require(_startAt >= block.timestamp, "start at < now");
+ require(_endAt >= _startAt, "end at < start at");
+ require(_endAt <= block.timestamp + 90 days, "end at > max duration");
+
+ count += 1;
+ campaigns[count] = Campaign({
+ creator: msg.sender,
+ goal: _goal,
+ pledged: 0,
+ startAt: _startAt,
+ endAt: _endAt,
+ claimed: false
+ });
+
+ emit Launch(count, msg.sender, _goal, _startAt, _endAt);
+ }
+
+ function cancel(uint _id) external {
+ Campaign memory campaign = campaigns[_id];
+ require(campaign.creator == msg.sender, "not creator");
+ require(block.timestamp < campaign.startAt, "started");
+
+ delete campaigns[_id];
+ emit Cancel(_id);
+ }
+
+ function pledge(uint _id, uint _amount) external {
+ Campaign storage campaign = campaigns[_id];
+ require(block.timestamp >= campaign.startAt, "not started");
+ require(block.timestamp <= campaign.endAt, "ended");
+
+ campaign.pledged += _amount;
+ pledgedAmount[_id][msg.sender] += _amount;
+ token.transferFrom(msg.sender, address(this), _amount);
+
+ emit Pledge(_id, msg.sender, _amount);
+ }
+
+ function unpledge(uint _id, uint _amount) external {
+ Campaign storage campaign = campaigns[_id];
+ require(block.timestamp <= campaign.endAt, "ended");
+
+ campaign.pledged -= _amount;
+ pledgedAmount[_id][msg.sender] -= _amount;
+ token.transfer(msg.sender, _amount);
+
+ emit Unpledge(_id, msg.sender, _amount);
+ }
+
+ function claim(uint _id) external {
+ Campaign storage campaign = campaigns[_id];
+ require(campaign.creator == msg.sender, "not creator");
+ require(block.timestamp > campaign.endAt, "not ended");
+ require(campaign.pledged >= campaign.goal, "pledged < goal");
+ require(!campaign.claimed, "claimed");
+
+ campaign.claimed = true;
+ token.transfer(campaign.creator, campaign.pledged);
+
+ emit Claim(_id);
+ }
+
+ function refund(uint _id) external {
+ Campaign memory campaign = campaigns[_id];
+ require(block.timestamp > campaign.endAt, "not ended");
+ require(campaign.pledged < campaign.goal, "pledged >= goal");
+
+ uint bal = pledgedAmount[_id][msg.sender];
+ pledgedAmount[_id][msg.sender] = 0;
+ token.transfer(msg.sender, bal);
+
+ emit Refund(_id, msg.sender, bal);
+ }
+}
+```
+
+## Teste no Remix
+
+- [CrowdFund.sol](https://remix.ethereum.org/#code=Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVApwcmFnbWEgc29saWRpdHkgXjAuOC4yMDsKCmludGVyZmFjZSBJRVJDMjAgewogICAgZnVuY3Rpb24gdHJhbnNmZXIoYWRkcmVzcywgdWludCkgZXh0ZXJuYWwgcmV0dXJucyAoYm9vbCk7CgogICAgZnVuY3Rpb24gdHJhbnNmZXJGcm9tKAogICAgICAgIGFkZHJlc3MsCiAgICAgICAgYWRkcmVzcywKICAgICAgICB1aW50CiAgICApIGV4dGVybmFsIHJldHVybnMgKGJvb2wpOwp9Cgpjb250cmFjdCBDcm93ZEZ1bmQgewogICAgZXZlbnQgTGF1bmNoKAogICAgICAgIHVpbnQgaWQsCiAgICAgICAgYWRkcmVzcyBpbmRleGVkIGNyZWF0b3IsCiAgICAgICAgdWludCBnb2FsLAogICAgICAgIHVpbnQzMiBzdGFydEF0LAogICAgICAgIHVpbnQzMiBlbmRBdAogICAgKTsKICAgIGV2ZW50IENhbmNlbCh1aW50IGlkKTsKICAgIGV2ZW50IFBsZWRnZSh1aW50IGluZGV4ZWQgaWQsIGFkZHJlc3MgaW5kZXhlZCBjYWxsZXIsIHVpbnQgYW1vdW50KTsKICAgIGV2ZW50IFVucGxlZGdlKHVpbnQgaW5kZXhlZCBpZCwgYWRkcmVzcyBpbmRleGVkIGNhbGxlciwgdWludCBhbW91bnQpOwogICAgZXZlbnQgQ2xhaW0odWludCBpZCk7CiAgICBldmVudCBSZWZ1bmQodWludCBpZCwgYWRkcmVzcyBpbmRleGVkIGNhbGxlciwgdWludCBhbW91bnQpOwoKICAgIHN0cnVjdCBDYW1wYWlnbiB7CiAgICAgICAgLy8gQ3JpYWRvciBkYSBjYW1wYW5oYQogICAgICAgIGFkZHJlc3MgY3JlYXRvcjsKICAgICAgICAvLyBRdWFudGlkYWRlIGRlIHRva2VucyBwYXJhIGFycmVjYWRhcgogICAgICAgIHVpbnQgZ29hbDsKICAgICAgICAvLyBWYWxvciB0b3RhbCBwcm9tZXRpZG8KICAgICAgICB1aW50IHBsZWRnZWQ7CiAgICAgICAgLy8gVGltZXN0YW1wIGRvIGluaWNpbyBkYSBjYW1wYW5oYQogICAgICAgIHVpbnQzMiBzdGFydEF0OwogICAgICAgIC8vIFRpbWVzdGFtcCBkbyBmaW5hbCBkYSBjYW1wYW5oYQogICAgICAgIHVpbnQzMiBlbmRBdDsKICAgICAgICAvLyBUcnVlIHNlIGEgbWV0YSBmb2kgYWxjYW5jYWRhIGUgbyBjcmlhZG9yIHJlaXZpbmRpY291IG9zIHRva2Vucy4KICAgICAgICBib29sIGNsYWltZWQ7CiAgICB9CgogICAgSUVSQzIwIHB1YmxpYyBpbW11dGFibGUgdG9rZW47CiAgICAvLyBDb250YWdlbSB0b3RhbCBkZSBjYW1wYW5oYXMgY3JpYWRhcy4KICAgIC8vIFRhbWJlbSBlIHVzYWRvIHBhcmEgZ2VyYXIgaWQgcGFyYSBub3ZhcyBjYW1wYW5oYXMuCiAgICB1aW50IHB1YmxpYyBjb3VudDsKICAgIC8vIE1hcHBpbmcgZG8gaWQgcGFyYSBvIENhbXBhaWduCiAgICBtYXBwaW5nKHVpbnQgPT4gQ2FtcGFpZ24pIHB1YmxpYyBjYW1wYWlnbnM7CiAgICAvLyBNYXBwaW5nIGRvIGNhbXBhaWduIGlkID0+IGRvYWRvciA9PiB2YWxvciBwcm9tZXRpZG8KICAgIG1hcHBpbmcodWludCA9PiBtYXBwaW5nKGFkZHJlc3MgPT4gdWludCkpIHB1YmxpYyBwbGVkZ2VkQW1vdW50OwoKICAgIGNvbnN0cnVjdG9yKGFkZHJlc3MgX3Rva2VuKSB7CiAgICAgICAgdG9rZW4gPSBJRVJDMjAoX3Rva2VuKTsKICAgIH0KCiAgICBmdW5jdGlvbiBsYXVuY2goCiAgICAgICAgdWludCBfZ29hbCwKICAgICAgICB1aW50MzIgX3N0YXJ0QXQsCiAgICAgICAgdWludDMyIF9lbmRBdAogICAgKSBleHRlcm5hbCB7CiAgICAgICAgcmVxdWlyZShfc3RhcnRBdCA+PSBibG9jay50aW1lc3RhbXAsICJzdGFydCBhdCA8IG5vdyIpOwogICAgICAgIHJlcXVpcmUoX2VuZEF0ID49IF9zdGFydEF0LCAiZW5kIGF0IDwgc3RhcnQgYXQiKTsKICAgICAgICByZXF1aXJlKF9lbmRBdCA8PSBibG9jay50aW1lc3RhbXAgKyA5MCBkYXlzLCAiZW5kIGF0ID4gbWF4IGR1cmF0aW9uIik7CgogICAgICAgIGNvdW50ICs9IDE7CiAgICAgICAgY2FtcGFpZ25zW2NvdW50XSA9IENhbXBhaWduKHsKICAgICAgICAgICAgY3JlYXRvcjogbXNnLnNlbmRlciwKICAgICAgICAgICAgZ29hbDogX2dvYWwsCiAgICAgICAgICAgIHBsZWRnZWQ6IDAsCiAgICAgICAgICAgIHN0YXJ0QXQ6IF9zdGFydEF0LAogICAgICAgICAgICBlbmRBdDogX2VuZEF0LAogICAgICAgICAgICBjbGFpbWVkOiBmYWxzZQogICAgICAgIH0pOwoKICAgICAgICBlbWl0IExhdW5jaChjb3VudCwgbXNnLnNlbmRlciwgX2dvYWwsIF9zdGFydEF0LCBfZW5kQXQpOwogICAgfQoKICAgIGZ1bmN0aW9uIGNhbmNlbCh1aW50IF9pZCkgZXh0ZXJuYWwgewogICAgICAgIENhbXBhaWduIG1lbW9yeSBjYW1wYWlnbiA9IGNhbXBhaWduc1tfaWRdOwogICAgICAgIHJlcXVpcmUoY2FtcGFpZ24uY3JlYXRvciA9PSBtc2cuc2VuZGVyLCAibm90IGNyZWF0b3IiKTsKICAgICAgICByZXF1aXJlKGJsb2NrLnRpbWVzdGFtcCA8IGNhbXBhaWduLnN0YXJ0QXQsICJzdGFydGVkIik7CgogICAgICAgIGRlbGV0ZSBjYW1wYWlnbnNbX2lkXTsKICAgICAgICBlbWl0IENhbmNlbChfaWQpOwogICAgfQoKICAgIGZ1bmN0aW9uIHBsZWRnZSh1aW50IF9pZCwgdWludCBfYW1vdW50KSBleHRlcm5hbCB7CiAgICAgICAgQ2FtcGFpZ24gc3RvcmFnZSBjYW1wYWlnbiA9IGNhbXBhaWduc1tfaWRdOwogICAgICAgIHJlcXVpcmUoYmxvY2sudGltZXN0YW1wID49IGNhbXBhaWduLnN0YXJ0QXQsICJub3Qgc3RhcnRlZCIpOwogICAgICAgIHJlcXVpcmUoYmxvY2sudGltZXN0YW1wIDw9IGNhbXBhaWduLmVuZEF0LCAiZW5kZWQiKTsKCiAgICAgICAgY2FtcGFpZ24ucGxlZGdlZCArPSBfYW1vdW50OwogICAgICAgIHBsZWRnZWRBbW91bnRbX2lkXVttc2cuc2VuZGVyXSArPSBfYW1vdW50OwogICAgICAgIHRva2VuLnRyYW5zZmVyRnJvbShtc2cuc2VuZGVyLCBhZGRyZXNzKHRoaXMpLCBfYW1vdW50KTsKCiAgICAgICAgZW1pdCBQbGVkZ2UoX2lkLCBtc2cuc2VuZGVyLCBfYW1vdW50KTsKICAgIH0KCiAgICBmdW5jdGlvbiB1bnBsZWRnZSh1aW50IF9pZCwgdWludCBfYW1vdW50KSBleHRlcm5hbCB7CiAgICAgICAgQ2FtcGFpZ24gc3RvcmFnZSBjYW1wYWlnbiA9IGNhbXBhaWduc1tfaWRdOwogICAgICAgIHJlcXVpcmUoYmxvY2sudGltZXN0YW1wIDw9IGNhbXBhaWduLmVuZEF0LCAiZW5kZWQiKTsKCiAgICAgICAgY2FtcGFpZ24ucGxlZGdlZCAtPSBfYW1vdW50OwogICAgICAgIHBsZWRnZWRBbW91bnRbX2lkXVttc2cuc2VuZGVyXSAtPSBfYW1vdW50OwogICAgICAgIHRva2VuLnRyYW5zZmVyKG1zZy5zZW5kZXIsIF9hbW91bnQpOwoKICAgICAgICBlbWl0IFVucGxlZGdlKF9pZCwgbXNnLnNlbmRlciwgX2Ftb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gY2xhaW0odWludCBfaWQpIGV4dGVybmFsIHsKICAgICAgICBDYW1wYWlnbiBzdG9yYWdlIGNhbXBhaWduID0gY2FtcGFpZ25zW19pZF07CiAgICAgICAgcmVxdWlyZShjYW1wYWlnbi5jcmVhdG9yID09IG1zZy5zZW5kZXIsICJub3QgY3JlYXRvciIpOwogICAgICAgIHJlcXVpcmUoYmxvY2sudGltZXN0YW1wID4gY2FtcGFpZ24uZW5kQXQsICJub3QgZW5kZWQiKTsKICAgICAgICByZXF1aXJlKGNhbXBhaWduLnBsZWRnZWQgPj0gY2FtcGFpZ24uZ29hbCwgInBsZWRnZWQgPCBnb2FsIik7CiAgICAgICAgcmVxdWlyZSghY2FtcGFpZ24uY2xhaW1lZCwgImNsYWltZWQiKTsKCiAgICAgICAgY2FtcGFpZ24uY2xhaW1lZCA9IHRydWU7CiAgICAgICAgdG9rZW4udHJhbnNmZXIoY2FtcGFpZ24uY3JlYXRvciwgY2FtcGFpZ24ucGxlZGdlZCk7CgogICAgICAgIGVtaXQgQ2xhaW0oX2lkKTsKICAgIH0KCiAgICBmdW5jdGlvbiByZWZ1bmQodWludCBfaWQpIGV4dGVybmFsIHsKICAgICAgICBDYW1wYWlnbiBtZW1vcnkgY2FtcGFpZ24gPSBjYW1wYWlnbnNbX2lkXTsKICAgICAgICByZXF1aXJlKGJsb2NrLnRpbWVzdGFtcCA+IGNhbXBhaWduLmVuZEF0LCAibm90IGVuZGVkIik7CiAgICAgICAgcmVxdWlyZShjYW1wYWlnbi5wbGVkZ2VkIDwgY2FtcGFpZ24uZ29hbCwgInBsZWRnZWQgPj0gZ29hbCIpOwoKICAgICAgICB1aW50IGJhbCA9IHBsZWRnZWRBbW91bnRbX2lkXVttc2cuc2VuZGVyXTsKICAgICAgICBwbGVkZ2VkQW1vdW50W19pZF1bbXNnLnNlbmRlcl0gPSAwOwogICAgICAgIHRva2VuLnRyYW5zZmVyKG1zZy5zZW5kZXIsIGJhbCk7CgogICAgICAgIGVtaXQgUmVmdW5kKF9pZCwgbXNnLnNlbmRlciwgYmFsKTsKICAgIH0KfQ==&version=soljson-v0.8.20+commit.a1b79de6.js)