Skip to content

Commit

Permalink
feat: diamond bond test with foundry
Browse files Browse the repository at this point in the history
tested makefile on bpaas

tested make file
  • Loading branch information
bl0up committed Apr 30, 2024
1 parent c51921a commit 7351b1a
Show file tree
Hide file tree
Showing 11 changed files with 443 additions and 272 deletions.
130 changes: 21 additions & 109 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,59 +24,14 @@ anvil:
@anvil

deploy-anvil:
@echo "Deploying DiamondCutFacet..."
@forge create ./src/facets/DiamondCutFacet.sol:DiamondCutFacet --rpc-url anvil --interactive | sed 's/Deployed to:/Deployed DiamondCut to:/g' | sed 's/Transaction hash:/Transaction hash DiamondCut:/g' | tee deployment-anvil.txt
@forge create ./src/Diamond.sol:Diamond --rpc-url anvil --interactive --constructor-args 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 "$$(grep "Deployed DiamondCut to:" deployment-anvil.txt | awk '{print $$4}')" | sed 's/Deployed to:/Deployed Diamond to:/g' | sed 's/Transaction hash:/Transaction hash Diamond:/g' | tee -a deployment-anvil.txt
@forge create ./src/upgradeInitializers/DiamondInit.sol:DiamondInit --rpc-url anvil --interactive | sed 's/Deployed to:/Deployed DiamondInit to:/g' | sed 's/Transaction hash:/Transaction hash DiamondInit:/g' | tee -a deployment-anvil.txt
@forge create ./src/GenericToken.sol:GenericToken --rpc-url anvil --interactive --constructor-args "GenericToken" "GT" | sed 's/Deployed to:/Deployed GenericToken to:/g' | sed 's/Transaction hash:/Transaction hash GenericToken:/g' | tee -a deployment-anvil.txt
@forge create ./src/facets/OwnershipFacet.sol:OwnershipFacet --rpc-url anvil --interactive | sed 's/Deployed to:/Deployed OwnershipFacet to:/g' | sed 's/Transaction hash:/Transaction hash OwnershipFacet:/g' | tee -a deployment-anvil.txt
@forge create ./src/facets/ERC1155Facet.sol:ERC1155Facet --rpc-url anvil --interactive | sed 's/Deployed to:/Deployed ERC1155Facet to:/g' | sed 's/Transaction hash:/Transaction hash ERC1155Facet:/g' | tee -a deployment-anvil.txt
@forge create ./src/facets/DiamondLoupeFacet.sol:DiamondLoupeFacet --rpc-url anvil --interactive | sed 's/Deployed to:/Deployed DiamondLoupeFacet to:/g' | sed 's/Transaction hash:/Transaction hash DiamondLoupeFacet:/g' | tee -a deployment-anvil.txt
@forge create ./src/facets/BondFacet.sol:BondFacet --rpc-url anvil --interactive | sed 's/Deployed to:/Deployed BondFacet to:/g' | sed 's/Transaction hash:/Transaction hash BondFacet:/g' | tee -a deployment-anvil.txt
@echo "Retrieving selectors for each facet..."
$(eval ADDRESS_OWNERSHIP=$(shell grep "Deployed OwnershipFacet to:" deployment-anvil.txt | awk '{print $$4}'))
$(eval ADDRESS_ERC1155=$(shell grep "Deployed ERC1155Facet to:" deployment-anvil.txt | awk '{print $$4}'))
$(eval ADDRESS_LOUPE=$(shell grep "Deployed DiamondLoupeFacet to:" deployment-anvil.txt | awk '{print $$4}'))
$(eval ADDRESS_BOND=$(shell grep "Deployed BondFacet to:" deployment-anvil.txt | awk '{print $$4}'))

@cast call $(ADDRESS_OWNERSHIP) "getSelectors()" --rpc-url anvil | tee selectors-ownership.txt
@cast call $(ADDRESS_ERC1155) "getSelectors()" --rpc-url anvil | tee selectors-erc1155.txt
@cast call $(ADDRESS_LOUPE) "getSelectors()" --rpc-url anvil | tee selectors-loupe.txt
@cast call $(ADDRESS_BOND) "getSelectors()" --rpc-url anvil | tee selectors-bond.txt
@sleep 2
@echo "Preparing for diamond cut..."
# Extract the addresses
$(eval DIAMOND_ADDRESS=$(shell grep "Deployed Diamond to:" deployment-anvil.txt | awk '{print $$4}'))
$(eval DIAMOND_INIT_ADDRESS=$(shell grep "Deployed DiamondInit to:" deployment-anvil.txt | awk '{print $$4}'))

# Extract and format the selectors from files
$(eval SELECTORS_OWNERSHIP=$(shell cat selectors-ownership.txt | sed -e 's/^.\{130\}//' | sed -e 's/\(.\{8\}\).\{56\}/"\1",/g' | sed '$$ s/,$$/]/'))
$(eval SELECTORS_ERC1155=$(shell cat selectors-erc1155.txt | sed -e 's/^.\{130\}//' | sed -e 's/\(.\{8\}\).\{56\}/"\1",/g' | sed '$$ s/,$$/]/'))
$(eval SELECTORS_LOUPE=$(shell cat selectors-loupe.txt | sed -e 's/^.\{130\}//' | sed -e 's/\(.\{8\}\).\{56\}/"\1",/g' | sed '$$ s/,$$/]/'))
$(eval SELECTORS_BOND=$(shell cat selectors-bond.txt | sed -e 's/^.\{130\}//' | sed -e 's/\(.\{8\}\).\{56\}/"\1",/g' | sed '$$ s/,$$/]/'))

# Addresses of the facets (assuming these are also logged in deployment-anvil.txt)
$(eval ADDRESS_OWNERSHIP=$(shell grep "Deployed OwnershipFacet to:" deployment-anvil.txt | awk '{print $$4}'))
$(eval ADDRESS_ERC1155=$(shell grep "Deployed ERC1155Facet to:" deployment-anvil.txt | awk '{print $$4}'))
$(eval ADDRESS_LOUPE=$(shell grep "Deployed DiamondLoupeFacet to:" deployment-anvil.txt | awk '{print $$4}'))
$(eval ADDRESS_BOND=$(shell grep "Deployed BondFacet to:" deployment-anvil.txt | awk '{print $$4}'))

# Encode function call for initialization
$(eval INIT_CALL=$(shell cast sig "init()"))

# Perform the diamond cut using cast
@cast send --interactive --rpc-url anvil $(DIAMOND_ADDRESS) "diamondCut((address,uint8,bytes4[])[],address,bytes)" \
"[($(ADDRESS_OWNERSHIP),0,[$(SELECTORS_OWNERSHIP)]),($(ADDRESS_ERC1155),0,[$(SELECTORS_ERC1155)]),($(ADDRESS_LOUPE),0,[$(SELECTORS_LOUPE)]),($(ADDRESS_BOND),0,[$(SELECTORS_BOND)])]" \
"$(DIAMOND_INIT_ADDRESS)" \
"$(INIT_CALL)"

@echo "Diamond cut transaction broadcasted."
@echo "Deploying to Anvil..."
@forge script script/DeployDiamond.s.sol --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url anvil --broadcast --unlocked

deploy-btp:
@eval $$(curl -H "x-auth-token: $${BTP_SERVICE_TOKEN}" -s $${BTP_CLUSTER_MANAGER_URL}/ide/foundry/$${BTP_SCS_ID}/env | sed 's/^/export /'); \
args=""; \
if [ ! -z "$${BTP_FROM}" ]; then \
args="--unlocked --from $${BTP_FROM}"; \
args="--unlocked --sender $${BTP_FROM} --broadcast"; \
else \
echo "\033[1;33mWARNING: No keys are activated on the node, falling back to interactive mode...\033[0m"; \
echo ""; \
Expand All @@ -88,71 +43,28 @@ deploy-btp:
if [ "$${BTP_EIP_1559_ENABLED}" = "false" ]; then \
args="$$args --legacy"; \
fi; \
forge create ./src/facets/DiamondCutFacet.sol:DiamondCutFacet $${EXTRA_ARGS} --rpc-url $${BTP_RPC_URL} $$args | sed 's/Deployed to:/Deployed DiamondCut to:/g' | sed 's/Transaction hash:/Transaction hash DiamondCut:/g' | tee deployment.txt; \
forge create ./src/Diamond.sol:Diamond $${EXTRA_ARGS} --rpc-url $${BTP_RPC_URL} $$args --constructor-args $${BTP_FROM} "$$(grep "Deployed DiamondCut to:" deployment.txt | awk '{print $$4}')" | sed 's/Deployed to:/Deployed Diamond to:/g' | sed 's/Transaction hash:/Transaction hash Diamond:/g' |tee -a deployment.txt; \
forge create ./src/upgradeInitializers/DiamondInit.sol:DiamondInit $${EXTRA_ARGS} --rpc-url $${BTP_RPC_URL} $$args | sed 's/Deployed to:/Deployed DiamondInit to:/g' | sed 's/Transaction hash:/Transaction hash DiamondInit:/g' | tee -a deployment.txt; \
forge create ./src/GenericToken.sol:GenericToken $${EXTRA_ARGS} --rpc-url $${BTP_RPC_URL} $$args --constructor-args "GenericToken" "GT" | sed 's/Deployed to:/Deployed GenericToken to:/g' | sed 's/Transaction hash:/Transaction hash GenericToken:/g' | tee -a deployment.txt; \
forge create ./src/facets/OwnershipFacet.sol:OwnershipFacet $${EXTRA_ARGS} --rpc-url $${BTP_RPC_URL} $$args | sed 's/Deployed to:/Deployed OwnershipFacet to:/g' | sed 's/Transaction hash:/Transaction hash OwnershipFacet:/g' | tee -a deployment.txt; \
forge create ./src/facets/ERC1155Facet.sol:ERC1155Facet $${EXTRA_ARGS} --rpc-url $${BTP_RPC_URL} $$args | sed 's/Deployed to:/Deployed ERC1155Facet to:/g' | sed 's/Transaction hash:/Transaction hash ERC1155Facet:/g' | tee -a deployment.txt; \
forge create ./src/facets/DiamondLoupeFacet.sol:DiamondLoupeFacet $${EXTRA_ARGS} --rpc-url $${BTP_RPC_URL} $$args | sed 's/Deployed to:/Deployed DiamondLoupeFacet to:/g' | sed 's/Transaction hash:/Transaction hash DiamondLoupeFacet:/g' | tee -a deployment.txt; \
forge create ./src/facets/BondFacet.sol:BondFacet $${EXTRA_ARGS} --rpc-url $${BTP_RPC_URL} $$args | sed 's/Deployed to:/Deployed BondFacet to:/g' | sed 's/Transaction hash:/Transaction hash BondFacet:/g' | tee -a deployment.txt; \

@echo "Retrieving selectors for each facet..."
$(eval ADDRESS_OWNERSHIP=$(shell grep "Deployed OwnershipFacet to:" deployment.txt | awk '{print $$4}'))
$(eval ADDRESS_ERC1155=$(shell grep "Deployed ERC1155Facet to:" deployment.txt | awk '{print $$4}'))
$(eval ADDRESS_LOUPE=$(shell grep "Deployed DiamondLoupeFacet to:" deployment.txt | awk '{print $$4}'))
$(eval ADDRESS_BOND=$(shell grep "Deployed BondFacet to:" deployment.txt | awk '{print $$4}'))

@cast call $(ADDRESS_OWNERSHIP) "getSelectors()" --rpc-url $${BTP_RPC_URL} | tee selectors-ownership.txt
@cast call $(ADDRESS_ERC1155) "getSelectors()" --rpc-url $${BTP_RPC_URL} | tee selectors-erc1155.txt
@cast call $(ADDRESS_LOUPE) "getSelectors()" --rpc-url $${BTP_RPC_URL} | tee selectors-loupe.txt
@cast call $(ADDRESS_BOND) "getSelectors()" --rpc-url $${BTP_RPC_URL} | tee selectors-bond.txt
@sleep 3
@echo "Preparing for diamond cut..."

$(eval DIAMOND_ADDRESS=$(shell grep "Deployed Diamond to:" deployment.txt | awk '{print $$4}'))
$(eval DIAMOND_INIT_ADDRESS=$(shell grep "Deployed DiamondInit to:" deployment.txt | awk '{print $$4}'))

$(eval SELECTORS_OWNERSHIP=$(shell cat selectors-ownership.txt | sed -e 's/^.\{130\}//' | sed -e 's/\(.\{8\}\).\{56\}/"\1",/g' | sed '$$ s/,$$/]/'))
$(eval SELECTORS_ERC1155=$(shell cat selectors-erc1155.txt | sed -e 's/^.\{130\}//' | sed -e 's/\(.\{8\}\).\{56\}/"\1",/g' | sed '$$ s/,$$/]/'))
$(eval SELECTORS_LOUPE=$(shell cat selectors-loupe.txt | sed -e 's/^.\{130\}//' | sed -e 's/\(.\{8\}\).\{56\}/"\1",/g' | sed '$$ s/,$$/]/'))
$(eval SELECTORS_BOND=$(shell cat selectors-bond.txt | sed -e 's/^.\{130\}//' | sed -e 's/\(.\{8\}\).\{56\}/"\1",/g' | sed '$$ s/,$$/]/'))

@echo ${SELECTORS_OWNERSHIP}
@echo ${SELECTORS_ERC1155}
@echo ${SELECTORS_LOUPE}
@echo ${SELECTORS_BOND}



$(eval INIT_CALL=$(shell cast sig "init()"))

@eval $$(curl -H "x-auth-token: $${BTP_SERVICE_TOKEN}" -s $${BTP_CLUSTER_MANAGER_URL}/ide/foundry/$${BTP_SCS_ID}/env | sed 's/^/export /'); \
args=""; \
if [ ! -z "$${BTP_FROM}" ]; then \
args="--unlocked --from $${BTP_FROM}"; \
else \
echo "\033[1;33mWARNING: No keys are activated on the node, falling back to interactive mode...\033[0m"; \
echo ""; \
args="--interactive"; \
fi; \
if [ ! -z "$${BTP_GAS_PRICE}" ]; then \
args="$$args --gas-price $${BTP_GAS_PRICE}"; \
fi; \
if [ "$${BTP_EIP_1559_ENABLED}" = "false" ]; then \
args="$$args --legacy"; \
fi; \
cast send --rpc-url $${BTP_RPC_URL} $$args $(DIAMOND_ADDRESS) "diamondCut((address,uint8,bytes4[])[],address,bytes)" \
"[($(ADDRESS_OWNERSHIP),0,[$(SELECTORS_OWNERSHIP)]),($(ADDRESS_ERC1155),0,[$(SELECTORS_ERC1155)]),($(ADDRESS_LOUPE),0,[$(SELECTORS_LOUPE)]),($(ADDRESS_BOND),0,[$(SELECTORS_BOND)])]" \
"$(DIAMOND_INIT_ADDRESS)" \
"$(INIT_CALL)"

@echo "Diamond cut transaction broadcasted."
forge script script/DeployDiamond.s.sol $${args} --rpc-url $${BTP_RPC_URL} --json

subgraph:
@echo "Deploying the subgraph..."
@rm -Rf subgraph/subgraph.config.json
@DEPLOYED_ERC20_ADDRESS=$$(grep "Deployed GenericToken to:" deployment.txt | awk '{print $$4}') DEPLOYED_ADDRESS=$$(grep "Deployed Diamond to:" deployment.txt | awk '{print $$4}') TRANSACTION_HASH=$$(grep "Transaction hash Diamond:" deployment.txt | awk '{print $$4}') TRANSACTION_HASH_ERC20=$$(grep "Transaction hash GenericToken:" deployment.txt | awk '{print $$4}') BLOCK_NUMBER=$$(cast receipt --rpc-url btp $${TRANSACTION_HASH} | grep "blockNumber" | awk '{print $$2}' | sed '2d') BLOCK_NUMBER_ERC20=$$(cast receipt --rpc-url btp $${TRANSACTION_HASH_ERC20} | grep "blockNumber" | awk '{print $$2}' | sed '2d') yq e -p=json -o=json '.datasources[0].address = strenv(DEPLOYED_ADDRESS) | .datasources[0].startBlock = strenv(BLOCK_NUMBER) | .datasources[1].address = strenv(DEPLOYED_ADDRESS) | .datasources[1].startBlock = strenv(BLOCK_NUMBER_ERC20) | .chain = strenv(BTP_NODE_UNIQUE_NAME)' subgraph/subgraph.config.template.json > subgraph/subgraph.config.json
@CHAIN_ID=$$(cast chain-id --rpc-url $$BTP_RPC_URL); \
output=$$(jq '.transactions[] | \
select(.transactionType == "CREATE" and \
(.contractName == "GenericToken" or .contractName == "Diamond")) | \
if .contractName == "GenericToken" then \
{contractName: "GenericToken", contractAddress: (.contractAddress // "not available"), transactionHash: (.hash // "not available")} \
elif .contractName == "Diamond" then \
{contractName: "Diamond", contractAddress: (.contractAddress // "not available"), transactionHash: (.hash // "not available")} \
else empty end' broadcast/DeployDiamond.s.sol/$$CHAIN_ID/run-latest.json); \
export DEPLOYED_ERC20_ADDRESS=$$(echo "$$output" | jq -r 'select(.contractName == "GenericToken") | .contractAddress'); \
export TRANSACTION_HASH_ERC20=$$(echo "$$output" | jq -r 'select(.contractName == "GenericToken") | .transactionHash'); \
export DEPLOYED_ADDRESS=$$(echo "$$output" | jq -r 'select(.contractName == "Diamond") | .contractAddress'); \
export TRANSACTION_HASH=$$(echo "$$output" | jq -r 'select(.contractName == "Diamond") | .transactionHash'); \
export BLOCK_NUMBER=$$(cast receipt --rpc-url $${BTP_RPC_URL} $${TRANSACTION_HASH} | grep "^blockNumber" | awk '{print $$2}'); \
export BLOCK_NUMBER_ERC20=$$(cast receipt --rpc-url $${BTP_RPC_URL} $${TRANSACTION_HASH_ERC20} | grep "^blockNumber" | awk '{print $$2}'); \
yq e -p=json -o=json '.datasources[0].address = strenv(DEPLOYED_ADDRESS) | .datasources[0].startBlock = strenv(BLOCK_NUMBER) | .datasources[1].address = strenv(DEPLOYED_ERC20_ADDRESS) | .datasources[1].startBlock = strenv(BLOCK_NUMBER_ERC20) | .chain = strenv(BTP_NODE_UNIQUE_NAME)' subgraph/subgraph.config.template.json > subgraph/subgraph.config.json; \

@cd subgraph && npx graph-compiler --config subgraph.config.json --include node_modules/@openzeppelin/subgraphs/src/datasources ./datasources --export-schema --export-subgraph
@cd subgraph && yq e '.specVersion = "0.0.4"' -i generated/solidity-diamond-bond.subgraph.yaml
@cd subgraph && yq e '.description = "Solidity Token diamond-bond"' -i generated/solidity-diamond-bond.subgraph.yaml
Expand Down
69 changes: 69 additions & 0 deletions script/DeployDiamond.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "forge-std/Script.sol";
import "../src/facets/BondFacet.sol";
import "../src/facets/ERC1155Facet.sol";
import "../src/facets/DiamondCutFacet.sol";
import "../src/facets/DiamondLoupeFacet.sol";
import "../src/Diamond.sol";
import "../src/upgradeInitializers/DiamondInit.sol";
import {IDiamondCut} from "../src/interfaces/IDiamondCut.sol";
import {BondInitParams} from "../src/libraries/StructBondInit.sol";
import "../src/interfaces/IDiamond.sol";
import "../src/GenericToken.sol";

contract DeployDiamondScript is Script {
function run() public {
vm.startBroadcast();
address owner = msg.sender;
console.log(owner);

DiamondCutFacet diamondCut = new DiamondCutFacet();
address diamondCutAddress = address(diamondCut);

DiamondInit diamondInit = new DiamondInit();
address diamondInitAddress = address(diamondInit);

ERC1155Facet erc1155Facet = new ERC1155Facet();
address erc1155FacetAddress = address(erc1155Facet);

DiamondLoupeFacet diamondLoupeFacet = new DiamondLoupeFacet();
address diamondLoupeFacetAddress = address(diamondLoupeFacet);

BondFacet bondFacet = new BondFacet();
address bondFacetAddress = address(bondFacet);

IDiamond.FacetCut[] memory cuts = new IDiamond.FacetCut[](3);
cuts[0] = IDiamond.FacetCut({
facetAddress: erc1155FacetAddress,
action: IDiamond.FacetCutAction.Add,
functionSelectors: erc1155Facet.getSelectors()
});

cuts[1] = IDiamond.FacetCut({
facetAddress: diamondLoupeFacetAddress,
action: IDiamond.FacetCutAction.Add,
functionSelectors: diamondLoupeFacet.getSelectors()
});

cuts[2] = IDiamond.FacetCut({
facetAddress: bondFacetAddress,
action: IDiamond.FacetCutAction.Add,
functionSelectors: bondFacet.getSelectors()
});

DiamondArgs memory da = DiamondArgs({
owner: owner,
init: diamondInitAddress,
initCalldata: abi.encodeWithSelector(bytes4(keccak256("init()")))
});

Diamond diamond = new Diamond(cuts, da);
address diamondAddress = address(diamond);

new GenericToken("GenericToken", "GT");

vm.stopBroadcast();
}
}
72 changes: 44 additions & 28 deletions src/Diamond.sol
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
* \
* Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
*
* Implementation of a diamond.
* /*****************************************************************************
*/
import { LibDiamond } from "./libraries/LibDiamond.sol";
import { IDiamondCut } from "./interfaces/IDiamondCut.sol";
//******************************************************************************\
//* Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)
//* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
//*
//* Implementation of a diamond.
//******************************************************************************/

import {LibDiamond} from "./libraries/LibDiamond.sol";
import {IDiamondCut} from "./interfaces/IDiamondCut.sol";
import {IDiamondLoupe} from "./interfaces/IDiamondLoupe.sol";
import {IERC173} from "./interfaces/IERC173.sol";

// When no function exists for function called
error FunctionNotFound(bytes4 _functionSelector);

// This is used in diamond constructor
// more arguments are added to this struct
// this avoids stack too deep errors
struct DiamondArgs {
address owner;
address init;
bytes initCalldata;
}

contract Diamond {
constructor(address _contractOwner, address _diamondCutFacet) payable {
LibDiamond.setContractOwner(_contractOwner);

// Add the diamondCut external function from the diamondCutFacet
IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](1);
bytes4[] memory functionSelectors = new bytes4[](1);
functionSelectors[0] = IDiamondCut.diamondCut.selector;
cut[0] = IDiamondCut.FacetCut({
facetAddress: _diamondCutFacet,
action: IDiamondCut.FacetCutAction.Add,
functionSelectors: functionSelectors
});
LibDiamond.diamondCut(cut, address(0), "");
constructor(
IDiamondCut.FacetCut[] memory _diamondCut,
DiamondArgs memory _args
) payable {
LibDiamond.setContractOwner(_args.owner);
LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata);

// Code can be added here to perform actions and set state variables.
}

// Find facet for function that is called and execute the
Expand All @@ -38,8 +46,12 @@ contract Diamond {
ds.slot := position
}
// get facet from function selector
address facet = ds.facetAddressAndSelectorPosition[msg.sig].facetAddress;
require(facet != address(0), "Diamond: Function does not exist");
address facet = ds
.facetAddressAndSelectorPosition[msg.sig]
.facetAddress;
if (facet == address(0)) {
revert FunctionNotFound(msg.sig);
}
// Execute external function from facet using delegatecall and return any value.
assembly {
// copy function selector and any arguments
Expand All @@ -50,10 +62,14 @@ contract Diamond {
returndatacopy(0, 0, returndatasize())
// return any return value or error back to the caller
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}

receive() external payable { }
receive() external payable {}
}
Loading

0 comments on commit 7351b1a

Please sign in to comment.