Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add batchTransferAlchemicaWithGotchiIds #139

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 36 additions & 28 deletions contracts/RealmDiamond/facets/AlchemicaFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ contract AlchemicaFacet is Modifiers {

event SurveyingRoundProgressed(uint256 indexed _newRound);

event TransferTokensWithGotchiId(
address indexed _sender,
uint256 indexed _gotchiId,
address _tokenAddress,
address _targetAddress,
uint256 _amount
);

event TransferTokensToGotchi(address indexed _sender, uint256 indexed _gotchiId, address _tokenAddresses, uint256 _amount);

error ERC20TransferFailed(string _tokenName);
Expand Down Expand Up @@ -175,8 +183,8 @@ contract AlchemicaFacet is Modifiers {
}

function calculateTransferAmounts(uint256 _amount, uint256 _spilloverRate) internal pure returns (TransferAmounts memory) {
uint256 owner = (_amount * (bp - (_spilloverRate * 10**16))) / bp;
uint256 spill = (_amount * (_spilloverRate * 10**16)) / bp;
uint256 owner = (_amount * (bp - (_spilloverRate * 10 ** 16))) / bp;
uint256 spill = (_amount * (_spilloverRate * 10 ** 16)) / bp;
return TransferAmounts(owner, spill);
}

Expand All @@ -188,11 +196,7 @@ contract AlchemicaFacet is Modifiers {
/// @param _realmId Identifier of parcel to claim alchemica from
/// @param _gotchiId Identifier of Aavegotchi to use for alchemica collecction/claiming
/// @param _signature Message signature used for backend validation
function claimAvailableAlchemica(
uint256 _realmId,
uint256 _gotchiId,
bytes memory _signature
) external gameActive {
function claimAvailableAlchemica(uint256 _realmId, uint256 _gotchiId, bytes memory _signature) external gameActive {
//Check signature
require(
LibSignature.isValid(keccak256(abi.encode(_realmId, _gotchiId, s.lastClaimedAlchemica[_realmId])), _signature, s.backendPubKey),
Expand Down Expand Up @@ -231,12 +235,7 @@ contract AlchemicaFacet is Modifiers {
/// @param _gotchiId Identifier of parent ERC721 aavegotchi which alchemica is channeled to
/// @param _lastChanneled The last time alchemica was channeled in this _realmId
/// @param _signature Message signature used for backend validation
function channelAlchemica(
uint256 _realmId,
uint256 _gotchiId,
uint256 _lastChanneled,
bytes memory _signature
) external gameActive {
function channelAlchemica(uint256 _realmId, uint256 _gotchiId, uint256 _lastChanneled, bytes memory _signature) external gameActive {
AavegotchiDiamond diamond = AavegotchiDiamond(s.aavegotchiDiamond);

//gotchi CANNOT have active listing for lending
Expand Down Expand Up @@ -343,15 +342,32 @@ contract AlchemicaFacet is Modifiers {
}
}

function batchTransferAlchemicaWithGotchiIds(uint256[] calldata _gotchiIds, address[] calldata _targets, uint256[4][] calldata _amounts) external {
require(_gotchiIds.length == _amounts.length, "AlchemicaFacet: Mismatched array lengths");
require(_targets.length == _amounts.length, "AlchemicaFacet: Mismatched array lengths");

IERC20Mintable[4] memory alchemicas = [
IERC20Mintable(s.alchemicaAddresses[0]),
IERC20Mintable(s.alchemicaAddresses[1]),
IERC20Mintable(s.alchemicaAddresses[2]),
IERC20Mintable(s.alchemicaAddresses[3])
];

for (uint256 i = 0; i < _targets.length; i++) {
for (uint256 j = 0; j < _amounts[i].length; j++) {
if (_amounts[i][j] > 0) {
alchemicas[j].transferFrom(msg.sender, _targets[i], _amounts[i][j]);
emit TransferTokensWithGotchiId(msg.sender, _gotchiIds[i], s.alchemicaAddresses[j], _targets[i], _amounts[i][j]);
}
}
}
}

/// @notice Helper function to batch transfer alchemica to Aavegotchis
/// @param _gotchiIds Array of Gotchi IDs
/// @param _tokenAddresses Array of tokens to transfer
/// @param _amounts Nested array of amounts to transfer.
function batchTransferTokensToGotchis(
uint256[] calldata _gotchiIds,
address[] calldata _tokenAddresses,
uint256[][] calldata _amounts
) external {
function batchTransferTokensToGotchis(uint256[] calldata _gotchiIds, address[] calldata _tokenAddresses, uint256[][] calldata _amounts) external {
require(_gotchiIds.length == _amounts.length, "AlchemicaFacet: Mismatched array lengths");

for (uint256 i = 0; i < _gotchiIds.length; i++) {
Expand Down Expand Up @@ -393,11 +409,7 @@ contract AlchemicaFacet is Modifiers {
}
}

function _batchTransferTokens(
address[] memory _tokens,
uint256[] memory _amounts,
address _to
) internal {
function _batchTransferTokens(address[] memory _tokens, uint256[] memory _amounts, address _to) internal {
require(_tokens.length == _amounts.length, "Array legth mismatch");
require(_to != address(0), "Address Zero Transfer");
for (uint256 i; i < _tokens.length; i++) {
Expand All @@ -414,11 +426,7 @@ contract AlchemicaFacet is Modifiers {
}
}

function batchTransferTokens(
address[][] calldata _tokens,
uint256[][] calldata _amounts,
address[] calldata _to
) external {
function batchTransferTokens(address[][] calldata _tokens, uint256[][] calldata _amounts, address[] calldata _to) external {
require(_tokens.length == _amounts.length, "Array length mismatch");
require(_to.length == _amounts.length, "Array length mismatch");
for (uint256 i; i < _to.length; i++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { run, ethers, network } from "hardhat";
import { varsForNetwork } from "../../../constants";
import {
convertFacetAndSelectorsToString,
DeployUpgradeTaskArgs,
FacetsAndAddSelectors,
} from "../../../tasks/deployUpgrade";

export async function upgradeBatchTransferAlchemicaWithGotchiIds() {
const diamondUpgrader = "0xa370f2ADd2A9Fba8759147995d6A0641F8d7C119";

const c = await varsForNetwork(ethers);

const facets: FacetsAndAddSelectors[] = [
{
facetName: "AlchemicaFacet",
addSelectors: [
`function batchTransferAlchemicaWithGotchiIds(uint256[] calldata _gotchiIds, address[] calldata _targets, uint256[4][] calldata _amounts) external`,
],
removeSelectors: [],
},
];

const joined = convertFacetAndSelectorsToString(facets);

const args: DeployUpgradeTaskArgs = {
diamondUpgrader: diamondUpgrader,
diamondAddress: c.realmDiamond,
facetsAndAddSelectors: joined,
useLedger: true,
useMultisig: false,
initAddress: ethers.constants.AddressZero,
initCalldata: "0x",
};

await run("deployUpgrade", args);
}

if (require.main === module) {
upgradeBatchTransferAlchemicaWithGotchiIds()
.then(() => process.exit(0))
// .then(() => console.log('upgrade completed') /* process.exit(0) */)
.catch((error) => {
console.error(error);
process.exit(1);
});
}
57 changes: 57 additions & 0 deletions test/realm/testBatchTransferAlchemicaWithGotchiIds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { impersonate } from "../../scripts/helperFunctions";
import { ethers, network } from "hardhat";
import { AlchemicaFacet } from "../../typechain";
import { alchemica, maticVars } from "../../constants";
import { expect } from "chai";
import { upgradeBatchTransferAlchemicaWithGotchiIds } from "../../scripts/realm/upgrades/upgrade-batchTransferAlchemicaWithGotchiIds";

describe("Testing events on batchTransferTokensToGotchis", async function () {
const testAddress = "0x2c1a288353e136b9e4b467aadb307133fffeab25";
const testDestAddress = "0xb7601193f559de56D67FB8e6a2AF219b05BD36c7";
const testGotchiId = 24186;
const testAmounts = [
ethers.utils.parseEther("0.01"),
ethers.utils.parseEther("0.02"),
ethers.utils.parseEther("0.03"),
ethers.utils.parseEther("0.01"),
];

let alchemicaFacet: AlchemicaFacet;

before(async function () {
this.timeout(20000000);

await upgradeBatchTransferAlchemicaWithGotchiIds();

alchemicaFacet = (await ethers.getContractAt(
"AlchemicaFacet",
maticVars.realmDiamond
)) as AlchemicaFacet;
});

it("test upgrade", async function () {
alchemicaFacet = await impersonate(
testAddress,
alchemicaFacet,
ethers,
network
);
const receipt = await (
await alchemicaFacet.batchTransferAlchemicaWithGotchiIds(
[testGotchiId],
[testDestAddress],
[testAmounts]
)
).wait();
const events = receipt.events.filter(
(event) => event.event === "TransferTokensWithGotchiId"
);
expect(events.length).to.equal(4);

events.forEach((event, i) => {
expect(event.args._tokenAddress).to.equal(alchemica[i]);
expect(event.args._targetAddress).to.equal(testDestAddress);
expect(event.args._amount).to.equal(testAmounts[i]);
});
});
});