diff --git a/.gitmodules b/.gitmodules index 888d42d..b6c54f6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/Openzeppelin/openzeppelin-contracts +[submodule "lib/solmate"] + path = lib/solmate + url = https://github.com/transmissions11/solmate diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts new file mode 160000 index 0000000..b2970b9 --- /dev/null +++ b/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit b2970b96e5e2be297421cd7690e3502e49f7deff diff --git a/lib/solmate b/lib/solmate new file mode 160000 index 0000000..8d910d8 --- /dev/null +++ b/lib/solmate @@ -0,0 +1 @@ +Subproject commit 8d910d876f51c3b2585c9109409d601f600e68e1 diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 0000000..21b5979 --- /dev/null +++ b/remappings.txt @@ -0,0 +1,5 @@ +ds-test/=lib/solmate/lib/ds-test/src/ +erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/ +forge-std/=lib/forge-std/src/ +openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/ +solmate/=lib/solmate/src/ diff --git a/script/Counter.s.sol b/script/SendIt.s.sol similarity index 84% rename from script/Counter.s.sol rename to script/SendIt.s.sol index 0e546ab..d4bc3e8 100644 --- a/script/Counter.s.sol +++ b/script/SendIt.s.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.13; import "forge-std/Script.sol"; -contract CounterScript is Script { +contract S is Script { function setUp() public {} function run() public { diff --git a/src/Counter.sol b/src/Counter.sol deleted file mode 100644 index aded799..0000000 --- a/src/Counter.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -contract Counter { - uint256 public number; - - function setNumber(uint256 newNumber) public { - number = newNumber; - } - - function increment() public { - number++; - } -} diff --git a/src/SendIt.sol b/src/SendIt.sol new file mode 100644 index 0000000..d219f0f --- /dev/null +++ b/src/SendIt.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "solmate/tokens/ERC721.sol"; +import "solmate/tokens/ERC1155.sol"; + +contract SendIt { + + mapping(address => address) public addressVault; + + event TokenTransfer(address indexed contractAddress, uint256 tokenIndex, address indexed from, address indexed to); + + /************************* + Modifiers + **************************/ + + modifier onlyIfTokenOwner( + address contractAddress, + uint256 tokenIndex, + bool isERC1155 + ) { + if (isERC1155) { + require(ERC1155(contractAddress).balanceOf(msg.sender, tokenIndex) > 0, "You must own the token."); + } else { + require(msg.sender == ERC721(contractAddress).ownerOf(tokenIndex), "You must own the token."); + } + _; + } + + function updateVault(address vaultAddress) external { + addressVault[msg.sender] = vaultAddress; + } + + function contractTransfer( + address contractAddress, + uint256 tokenIndex, + address recipient, + bool isERC1155 + ) public { + if (isERC1155) { + require(ERC1155(contractAddress).balanceOf(msg.sender, tokenIndex) > 0, "Sender is not the token owner, cannot proceed with transfer."); + require(ERC1155(contractAddress).isApprovedForAll(msg.sender, address(this)), "Contract not approved to send token on Sender behalf."); + ERC1155(contractAddress).safeTransferFrom(msg.sender, recipient, tokenIndex, 1, bytes("")); + } else { + require(msg.sender == ERC721(contractAddress).ownerOf(tokenIndex), "Sender is not the token owner, cannot proceed with transfer."); + require(ERC721(contractAddress).getApproved(tokenIndex) == address(this), "Contract not approved to send token on Sender behalf."); + ERC721(contractAddress).safeTransferFrom(msg.sender, recipient, tokenIndex); + } + emit TokenTransfer(contractAddress, tokenIndex, msg.sender, recipient); + } + + function contractBulkTransfer( + address contractAddress, + uint256[] calldata tokenIndexes, + address[] calldata recipients, + bool isERC1155 + ) external { + require(tokenIndexes.length == recipients.length, "Array lengths must match."); + for(uint256 i; i < tokenIndexes.length; i++) { + contractTransfer(contractAddress, tokenIndexes[i], recipients[i], isERC1155); + } + } + +} diff --git a/test/Counter.t.sol b/test/Counter.t.sol deleted file mode 100644 index 30235e8..0000000 --- a/test/Counter.t.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import "forge-std/Test.sol"; -import "../src/Counter.sol"; - -contract CounterTest is Test { - Counter public counter; - - function setUp() public { - counter = new Counter(); - counter.setNumber(0); - } - - function testIncrement() public { - counter.increment(); - assertEq(counter.number(), 1); - } - - function testSetNumber(uint256 x) public { - counter.setNumber(x); - assertEq(counter.number(), x); - } -} diff --git a/test/SendIt.t.sol b/test/SendIt.t.sol new file mode 100644 index 0000000..c65632c --- /dev/null +++ b/test/SendIt.t.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "../src/SendIt.sol"; + +contract SendItTest is Test { + SendIt public sendit; + + function setUp() public { + sendit = new SendIt(); + } + + function testUpdateVault() public { + sendit.updateVault(address(3)); + assertEq(sendit.addressVault(address(0)), address(3)); + } +}