Skip to content

Commit

Permalink
swap UDT for UP
Browse files Browse the repository at this point in the history
  • Loading branch information
clemsos committed May 22, 2024
1 parent 7659287 commit 39b45b5
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 18 deletions.
75 changes: 61 additions & 14 deletions smart-contracts/contracts/tokens/UP/UPSwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ import "@openzeppelin/contracts-upgradeable5/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable5/proxy/utils/Initializable.sol";

contract UPSwap is Initializable, OwnableUpgradeable {
address public up;
address public udt;
IERC20 public up;
IERC20 public udt;

error AllowanceTooLow();
error BalanceTooLow();
error TransferFailed(address tokenAddress);

event UPSwapped(address sender, uint amount, address recipient);
event UDTSwapped(address sender, uint amount, address recipient);

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
Expand All @@ -22,21 +29,61 @@ contract UPSwap is Initializable, OwnableUpgradeable {
__Ownable_init(initialOwner);

// store addresses
up = _up;
udt = _udt;
up = IERC20(_up);
udt = IERC20(_udt);
}

function swapUDTForUP(
address sender,
uint amount,
address recipient
) public {}
function swapUDTForUP(address sender, uint amount, address recipient) public {
// check balance
if (udt.balanceOf(sender) < amount) {
revert BalanceTooLow();
}

function swapUPforUDT(
address sender,
uint amount,
address recipient
) public {}
// check allowance
if (udt.allowance(sender, address(this)) < amount) {
revert AllowanceTooLow();
}

// get the UDT from sender
bool UDTSent = udt.transferFrom(sender, address(this), amount);
if (!UDTSent) {
revert TransferFailed(address(udt));
}

// send UP token to recipient
bool UPSent = up.transfer(recipient, amount);
if (!UPSent) {
revert TransferFailed(address(up));
}

emit UDTSwapped(sender, amount, recipient);
}

function swapUPforUDT(address sender, uint amount, address recipient) public {
// check balance
if (up.balanceOf(sender) < amount) {
revert BalanceTooLow();
}

// check allowance
if (up.allowance(sender, address(this)) < amount) {
revert AllowanceTooLow();
}

// get UP token from sender
bool UPSent = up.transferFrom(sender, address(this), amount);
if (!UPSent) {
revert TransferFailed(address(up));
}

// send the UDT to recipient
bool UDTSent = udt.transfer(recipient, amount);
if (!UDTSent) {
revert TransferFailed(address(udt));
}

emit UPSwapped(sender, amount, recipient);
}

function swapUPForUDTWithSignature(
address sender,
Expand Down
124 changes: 120 additions & 4 deletions smart-contracts/test/UnlockProtocolToken/swap.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
const { assert } = require('chai')
const { ethers, upgrades } = require('hardhat')
const { deployContracts } = require('../helpers')
const { reverts } = require('../helpers')
const { getEvent } = require('@unlock-protocol/hardhat-helpers')

const amount = ethers.parseEther('10')

const parseLogs = (logs, interface) =>
logs.map((log) => {
const parsed = interface.parseLog(log)
return parsed ? parsed : log
})

describe('UPSwap / swap UDT for UP', () => {
let owner, preMinter
let owner, preMinter, sender, recipient
let up, udt, swap

before(async () => {
;[owner, preMinter] = await ethers.getSigners()
;({ udt } = await deployContracts())
;[owner, preMinter, sender, recipient] = await ethers.getSigners()

const UDT = await ethers.getContractFactory('UnlockDiscountTokenV3')
udt = await upgrades.deployProxy(UDT, [await preMinter.getAddress()], {
initializer: 'initialize(address)',
})

const UP = await ethers.getContractFactory('UnlockProtocolToken')
up = await upgrades.deployProxy(UP, [
Expand All @@ -22,6 +35,11 @@ describe('UPSwap / swap UDT for UP', () => {
await udt.getAddress(),
await owner.getAddress(),
])

// transfer entire UP supply to swap contract
await up
.connect(preMinter)
.transfer(await swap.getAddress(), await up.totalSupply())
})

describe('settings', () => {
Expand All @@ -37,4 +55,102 @@ describe('UPSwap / swap UDT for UP', () => {
assert.equal(await owner.getAddress(), await swap.owner())
})
})

describe('swapUDTForUP', () => {
describe('reverts', () => {
it('when balance is too low', async () => {
await reverts(
swap.swapUDTForUP(
await sender.getAddress(),
amount,
await recipient.getAddress()
),
'BalanceTooLow'
)
})
it('when allowance is not properly set', async () => {
await udt.connect(preMinter).mint(await sender.getAddress(), amount)
await reverts(
swap.swapUDTForUP(
await sender.getAddress(),
amount,
await recipient.getAddress()
),
'AllowanceTooLow'
)
})
})
describe('swap', () => {
let receipt, parsedLogs
let senderBalanceBefore
let swapBalanceBefore

before(async () => {
// prepare funds and allowance
await udt.connect(preMinter).mint(await sender.getAddress(), amount)
await udt.connect(sender).approve(await swap.getAddress(), amount)

// get balances
senderBalanceBefore = await udt.balanceOf(await sender.getAddress())
swapBalanceBefore = await udt.balanceOf(await swap.getAddress())

// do the swap
const tx = await swap.swapUDTForUP(
await sender.getAddress(),
amount,
await recipient.getAddress()
)

// parse receipt
receipt = await tx.wait()
parsedLogs = parseLogs(receipt.logs, udt.interface)
})

it('UP has been sent', async () => {
assert.equal(await up.balanceOf(await recipient.getAddress()), amount)
})
it('UDT has been transferred', async () => {
assert.equal(
await udt.balanceOf(await swap.getAddress()),
swapBalanceBefore + amount
)
assert.equal(
await udt.balanceOf(await sender.getAddress()),
senderBalanceBefore - amount
)
})

it('allowance is reset', async () => {
assert.equal(
await udt.allowance(
await sender.getAddress(),
await swap.getAddress()
),
0n
)

// approval reset event has been fired
const approvals = parsedLogs.filter(
({ fragment }) => fragment.name === 'Approval'
)
assert.equal(approvals.length, 1)
const [{ args: approvalArgs }] = approvals
assert.equal(approvalArgs[0], await sender.getAddress())
assert.equal(approvalArgs[1], await swap.getAddress())
assert.equal(approvalArgs[2], 0n)
})
it('fired Transfer events', async () => {
const transfers = parsedLogs.filter(
({ fragment }) => fragment.name === 'Transfer'
)
assert.equal(transfers.length, 2)
})
it('fired custom event', async () => {
const { args } = await getEvent(receipt, 'UDTSwapped')
assert.equal(await sender.getAddress(), args.sender)
assert.equal(await recipient.getAddress(), args.recipient)
assert.equal(amount, args.amount)
})
})
})
})

0 comments on commit 39b45b5

Please sign in to comment.