mirror of
https://github.com/0xShay/ticketchain.git
synced 2026-01-11 13:13:25 +00:00
add tests
This commit is contained in:
2240
cache/solidity-files-cache.json
vendored
2240
cache/solidity-files-cache.json
vendored
File diff suppressed because it is too large
Load Diff
@@ -2,174 +2,182 @@
|
||||
|
||||
pragma solidity >=0.8.2 <0.9.0;
|
||||
|
||||
import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol";
|
||||
/* THIS IS A TEST IMPORT, in production use: import {FtsoV2Interface} from "@flarenetwork/flare-periphery-contracts/coston2/FtsoV2Interface.sol"; */
|
||||
import {TestFtsoV2Interface} from "@flarenetwork/flare-periphery-contracts/coston2/TestFtsoV2Interface.sol";
|
||||
|
||||
contract EventManager {
|
||||
|
||||
struct Event {
|
||||
string name;
|
||||
string description;
|
||||
uint256 capacity;
|
||||
uint256 ticketsSold;
|
||||
uint256 ticketPrice; // in USD cents
|
||||
uint256 eventDate;
|
||||
string[] images; // array of image URLs
|
||||
uint256[] tickets;
|
||||
address eventHost;
|
||||
}
|
||||
|
||||
struct Ticket {
|
||||
address holder;
|
||||
uint256 boughtTime;
|
||||
uint256 eventId;
|
||||
}
|
||||
|
||||
mapping(uint256 => Event) public events;
|
||||
mapping(uint256 => Ticket) public tickets;
|
||||
|
||||
mapping(uint256 => mapping(address => bool)) ticketAllowance;
|
||||
|
||||
mapping(address => uint256[]) public userTickets;
|
||||
|
||||
uint256 public eventCounter;
|
||||
uint256 public ticketCounter;
|
||||
|
||||
function centsToFlare(uint256 _cents) public view returns (uint256 _flr) {
|
||||
return _cents*14/10;
|
||||
}
|
||||
|
||||
function power(uint base, int8 exponent) public pure returns (uint) {
|
||||
require(exponent >= 0, 'Exponent must be non-negative');
|
||||
uint result = 1;
|
||||
for (int8 i = 0; i < exponent; i++) {
|
||||
result *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getEventPriceFlare(
|
||||
uint256 _eventId
|
||||
) public view returns (uint256 _flr) {
|
||||
require(_eventId < eventCounter, 'Invalid event ID');
|
||||
return centsToFlare(events[_eventId].ticketPrice);
|
||||
}
|
||||
|
||||
function createEvent(
|
||||
string memory _name,
|
||||
string memory _description,
|
||||
uint256 _capacity,
|
||||
uint256 _ticketPrice,
|
||||
uint256 _eventDate,
|
||||
string[] memory _images
|
||||
) public {
|
||||
events[eventCounter] = Event(
|
||||
_name,
|
||||
_description,
|
||||
_capacity,
|
||||
0,
|
||||
_ticketPrice,
|
||||
_eventDate,
|
||||
_images,
|
||||
new uint256[](0),
|
||||
msg.sender
|
||||
);
|
||||
eventCounter++;
|
||||
}
|
||||
|
||||
function getEventImages(
|
||||
uint256 _eventId
|
||||
) public view returns (string[] memory) {
|
||||
require(_eventId < eventCounter, 'Invalid event ID');
|
||||
return events[_eventId].images;
|
||||
}
|
||||
|
||||
function getEventTickets(
|
||||
uint256 _eventId
|
||||
) public view returns (uint256[] memory) {
|
||||
require(_eventId < eventCounter, 'Invalid event ID');
|
||||
return events[_eventId].tickets;
|
||||
}
|
||||
|
||||
//TODO: ADD CURRENCY CONVERSION + CHECK
|
||||
function buyTicket(uint256 _eventId) public payable {
|
||||
require(_eventId < eventCounter, 'Invalid event ID');
|
||||
require(
|
||||
events[_eventId].eventDate > block.timestamp,
|
||||
'Event has already passed'
|
||||
);
|
||||
require(
|
||||
events[_eventId].tickets.length < events[_eventId].capacity,
|
||||
'Event is full'
|
||||
);
|
||||
require(msg.value == events[_eventId].ticketPrice, 'Invalid ticket price');
|
||||
|
||||
// Create new ticket
|
||||
tickets[ticketCounter] = Ticket(msg.sender, block.timestamp, _eventId);
|
||||
|
||||
// Add ticket to user
|
||||
userTickets[msg.sender].push(ticketCounter);
|
||||
|
||||
ticketCounter++;
|
||||
|
||||
// Update number of tickets sold
|
||||
events[_eventId].ticketsSold++;
|
||||
|
||||
// Transfer FLR to event host
|
||||
(bool sent, ) = events[_eventId].eventHost.call{value: msg.value}('');
|
||||
require(sent, 'Failed to send FLR to event host');
|
||||
}
|
||||
|
||||
function transferTicketForce(uint256 _ticketId, address _to) private {
|
||||
require(_ticketId < ticketCounter, 'Invalid ticket ID');
|
||||
require(
|
||||
events[tickets[_ticketId].eventId].eventDate > block.timestamp,
|
||||
'Event has already passed'
|
||||
);
|
||||
|
||||
address prevHolder = tickets[_ticketId].holder;
|
||||
|
||||
// Get index of ticket in holder's array
|
||||
bool found = false;
|
||||
uint256 i = 0;
|
||||
for (; i < userTickets[prevHolder].length; i++) {
|
||||
if (userTickets[prevHolder][i] == _ticketId) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
struct Event {
|
||||
string name;
|
||||
string description;
|
||||
uint256 capacity;
|
||||
uint256 ticketsSold;
|
||||
uint256 ticketPrice; // in USD cents
|
||||
uint256 eventDate;
|
||||
string[] images; // array of image URLs
|
||||
uint256[] tickets;
|
||||
address payable eventHost;
|
||||
}
|
||||
|
||||
require(found, "Ticket not found in sender's inventory");
|
||||
|
||||
// Remove ticket from holder's array
|
||||
for (; i < userTickets[prevHolder].length; i++) {
|
||||
userTickets[prevHolder][i] = userTickets[prevHolder][i + 1];
|
||||
struct Ticket {
|
||||
address holder;
|
||||
uint256 boughtTime;
|
||||
uint256 eventId;
|
||||
}
|
||||
|
||||
// Add ticket to _to's array
|
||||
userTickets[_to].push(_ticketId);
|
||||
event EventCreated(uint256 eventId, string name, uint256 eventDate);
|
||||
event TicketPurchased(uint256 ticketId, uint256 eventId, address buyer, uint256 price);
|
||||
event TicketTransferred(uint256 ticketId, address from, address to);
|
||||
event TicketTransferApproved(uint256 ticketId, address owner, address trustee);
|
||||
|
||||
tickets[_ticketId].holder = _to;
|
||||
}
|
||||
mapping(uint256 => Event) public events;
|
||||
mapping(uint256 => Ticket) public tickets;
|
||||
|
||||
function approveTicket(uint256 _ticketId, address _to, bool _allowed) public {
|
||||
require(_ticketId < ticketCounter, 'Invalid ticket ID');
|
||||
require(
|
||||
tickets[_ticketId].holder == msg.sender,
|
||||
'You do not own this ticket'
|
||||
);
|
||||
ticketAllowance[_ticketId][_to] = _allowed;
|
||||
}
|
||||
mapping(uint256 => mapping(address => bool)) ticketAllowance;
|
||||
|
||||
function transferTicket(uint256 _ticketId, address _to) public {
|
||||
require(_ticketId < ticketCounter, 'Invalid ticket ID');
|
||||
require(
|
||||
tickets[_ticketId].holder == msg.sender ||
|
||||
tickets[_ticketId].holder == msg.sender,
|
||||
'You do not own this ticket'
|
||||
);
|
||||
require(
|
||||
ticketAllowance[_ticketId][msg.sender],
|
||||
'You are not allowed to transfer this ticket'
|
||||
);
|
||||
ticketAllowance[_ticketId][msg.sender] = false;
|
||||
transferTicketForce(_ticketId, _to);
|
||||
}
|
||||
}
|
||||
mapping(address => uint256[]) public userTickets;
|
||||
|
||||
uint256 public eventCounter;
|
||||
uint256 public ticketCounter;
|
||||
|
||||
function getFtsoV2CurrentFeedValues() public view returns (
|
||||
uint256[] memory _feedValues,
|
||||
int8[] memory _decimals,
|
||||
uint64 _timestamp
|
||||
) {
|
||||
return ftsoV2.getFeedsById(feedIds);
|
||||
}
|
||||
|
||||
function getFlareFeed() public view returns (uint256 _feedValue, int8 _decimals, uint64 _timestamp) {
|
||||
uint256[] memory feedValues;
|
||||
int8[] memory decimals;
|
||||
uint64 timestamp;
|
||||
(feedValues, decimals, timestamp) = ftsoV2.getFeedsById(feedIds);
|
||||
return (feedValues[0], decimals[0], timestamp);
|
||||
}
|
||||
|
||||
function centsToFlare(uint256 _cents) public view returns (uint256 _flr) {
|
||||
uint256 feedValue;
|
||||
int8 decimals;
|
||||
(feedValue, decimals, ) = getFlareFeed();
|
||||
return _cents * power(10, decimals) * 1 ether / 100 / feedValue;
|
||||
}
|
||||
|
||||
function power(uint base, int8 exponent) private pure returns (uint) {
|
||||
require(exponent >= 0, "Exponent must be non-negative");
|
||||
uint result = 1;
|
||||
for (int8 i = 0; i < exponent; i++) {
|
||||
result *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getEventPriceFlare(uint256 _eventId) public view returns (uint256 _flr) {
|
||||
require(_eventId < eventCounter, "Invalid event ID");
|
||||
return centsToFlare(events[_eventId].ticketPrice);
|
||||
}
|
||||
|
||||
function createEvent(string memory _name, string memory _description, uint256 _capacity, uint256 _ticketPrice, uint256 _eventDate, string[] memory _images) public returns (uint256 _eventId) {
|
||||
events[eventCounter] = Event(_name, _description, _capacity, 0, _ticketPrice, _eventDate, _images, new uint256[](0), payable(msg.sender));
|
||||
eventCounter++;
|
||||
emit EventCreated(eventCounter - 1, _name, _eventDate);
|
||||
return eventCounter - 1;
|
||||
}
|
||||
|
||||
function getEventImages(uint256 _eventId) public view returns (string[] memory) {
|
||||
require(_eventId < eventCounter, "Invalid event ID");
|
||||
return events[_eventId].images;
|
||||
}
|
||||
|
||||
function getEventTickets(uint256 _eventId) public view returns (uint256[] memory) {
|
||||
require(_eventId < eventCounter, "Invalid event ID");
|
||||
return events[_eventId].tickets;
|
||||
}
|
||||
|
||||
function buyTicket(uint256 _eventId) public payable returns (uint256 _ticketId) {
|
||||
require(_eventId < eventCounter, "Invalid event ID");
|
||||
require(events[_eventId].eventDate > block.timestamp, "Event has already passed");
|
||||
require(events[_eventId].tickets.length < events[_eventId].capacity, "Event is full");
|
||||
|
||||
uint256 ticketCost = getEventPriceFlare(_eventId); // Get ticket price in FLR
|
||||
require(msg.value >= ticketCost, "Insufficient value provided"); // Ensure user has paid >= ticket price
|
||||
if (msg.value > ticketCost) {
|
||||
// Pay any excess the user paid
|
||||
(bool sentExcess, ) = msg.sender.call{value: msg.value - ticketCost}("");
|
||||
require(sentExcess, "Failed to send FLR excess back to buyer");
|
||||
}
|
||||
|
||||
// Create new ticket
|
||||
tickets[ticketCounter] = Ticket(msg.sender, block.timestamp, _eventId);
|
||||
|
||||
// Add ticket to user
|
||||
userTickets[msg.sender].push(ticketCounter);
|
||||
|
||||
ticketCounter++;
|
||||
|
||||
// Update number of tickets sold
|
||||
events[_eventId].tickets.push(ticketCounter - 1);
|
||||
events[_eventId].ticketsSold++;
|
||||
|
||||
// Transfer FLR to event host
|
||||
(bool sentToHost, ) = events[_eventId].eventHost.call{value: ticketCost}("");
|
||||
require(sentToHost, "Failed to send FLR to event host");
|
||||
|
||||
emit TicketPurchased(ticketCounter - 1, _eventId, msg.sender, ticketCost);
|
||||
return ticketCounter - 1;
|
||||
}
|
||||
|
||||
function transferTicketForce(uint256 _ticketId, address _to) private {
|
||||
require(_ticketId < ticketCounter, "Invalid ticket ID");
|
||||
require(events[tickets[_ticketId].eventId].eventDate > block.timestamp, "Event has already passed");
|
||||
|
||||
address prevHolder = tickets[_ticketId].holder;
|
||||
|
||||
// Get index of ticket in holder's array
|
||||
bool found = false;
|
||||
uint256 i = 0;
|
||||
for (; i < userTickets[prevHolder].length; i++) {
|
||||
if (userTickets[prevHolder][i] == _ticketId) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
require(found, "Ticket not found in sender's inventory");
|
||||
|
||||
// Remove ticket from holder's array
|
||||
for (; i < userTickets[prevHolder].length-1; i++) {
|
||||
userTickets[prevHolder][i] = userTickets[prevHolder][i+1];
|
||||
}
|
||||
userTickets[prevHolder].pop();
|
||||
|
||||
// Add ticket to _to's array
|
||||
userTickets[_to].push(_ticketId);
|
||||
|
||||
tickets[_ticketId].holder = _to;
|
||||
|
||||
emit TicketTransferred(_ticketId, prevHolder, _to);
|
||||
}
|
||||
|
||||
function approveTicket(uint256 _ticketId, address _to, bool _allowed) public {
|
||||
require(_ticketId < ticketCounter, "Invalid ticket ID");
|
||||
require(tickets[_ticketId].holder == msg.sender, "You do not own this ticket");
|
||||
ticketAllowance[_ticketId][_to] = _allowed;
|
||||
|
||||
emit TicketTransferApproved(_ticketId, msg.sender, _to);
|
||||
}
|
||||
|
||||
function transferTicketFrom(uint256 _ticketId, address _to) public {
|
||||
require(ticketAllowance[_ticketId][msg.sender], "You are not allowed to transfer this ticket");
|
||||
ticketAllowance[_ticketId][msg.sender] = false;
|
||||
transferTicketForce(_ticketId, _to);
|
||||
}
|
||||
|
||||
function transferTicket(uint256 _ticketId, address _to) public {
|
||||
require(_ticketId < ticketCounter, "Invalid ticket ID");
|
||||
require(tickets[_ticketId].holder == msg.sender, "You do not own this ticket");
|
||||
transferTicketForce(_ticketId, _to);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
import { HardhatUserConfig } from "hardhat/config";
|
||||
import "@nomicfoundation/hardhat-toolbox";
|
||||
import "@nomiclabs/hardhat-ethers";
|
||||
import { HardhatUserConfig } from 'hardhat/config';
|
||||
import '@nomiclabs/hardhat-waffle';
|
||||
import '@nomiclabs/hardhat-ethers';
|
||||
|
||||
const config: HardhatUserConfig = {
|
||||
solidity: "0.8.19",
|
||||
paths: {
|
||||
sources: "./contracts",
|
||||
tests: "./test",
|
||||
cache: "./cache",
|
||||
artifacts: "./artifacts"
|
||||
solidity: '0.8.17',
|
||||
networks: {
|
||||
hardhat: {
|
||||
chainId: 1337,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
export default config;
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { expect } from "chai";
|
||||
import { ethers } from "hardhat";
|
||||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||
import { EventManager } from "../typechain-types/EventManager";
|
||||
import { expect } from 'chai';
|
||||
import { ethers } from 'hardhat';
|
||||
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
|
||||
import { EventManager } from '../typechain-types/EventManager';
|
||||
|
||||
describe("EventManager", function () {
|
||||
describe('EventManager', function () {
|
||||
let eventManager: EventManager;
|
||||
let owner: SignerWithAddress;
|
||||
let addr1: SignerWithAddress;
|
||||
let addr2: SignerWithAddress;
|
||||
|
||||
const EVENT_NAME = "Test Event";
|
||||
const EVENT_DESCRIPTION = "This is a test event";
|
||||
const EVENT_NAME = 'Test Event';
|
||||
const EVENT_DESCRIPTION = 'This is a test event';
|
||||
const EVENT_CAPACITY = 100;
|
||||
const EVENT_TICKET_PRICE = 1000; // 10 USD in cents
|
||||
const EVENT_DATE = Math.floor(Date.now() / 1000) + 86400; // 1 day from now
|
||||
const EVENT_IMAGES = ["image1.jpg", "image2.jpg"];
|
||||
const EVENT_IMAGES = ['image1.jpg', 'image2.jpg'];
|
||||
|
||||
beforeEach(async function () {
|
||||
[owner, addr1, addr2] = await ethers.getSigners();
|
||||
|
||||
const EventManager = await ethers.getContractFactory("EventManager");
|
||||
const EventManager = await ethers.getContractFactory('EventManager');
|
||||
eventManager = await EventManager.deploy();
|
||||
await eventManager.deployed();
|
||||
});
|
||||
@@ -35,35 +35,37 @@ describe("EventManager", function () {
|
||||
);
|
||||
}
|
||||
|
||||
describe("Event Creation", function () {
|
||||
it("Should create an event with correct details", async function () {
|
||||
await createTestEvent();
|
||||
// describe("Event Creation", function () {
|
||||
// it("Should create an event with correct details", async function () {
|
||||
// await createTestEvent();
|
||||
|
||||
const event = await eventManager.events(0);
|
||||
expect(event.name).to.equal(EVENT_NAME);
|
||||
expect(event.description).to.equal(EVENT_DESCRIPTION);
|
||||
expect(event.capacity).to.equal(EVENT_CAPACITY);
|
||||
expect(event.ticketPrice).to.equal(EVENT_TICKET_PRICE);
|
||||
expect(event.eventDate).to.equal(EVENT_DATE);
|
||||
expect(event.eventHost).to.equal(owner.address);
|
||||
});
|
||||
// const event = await eventManager.events(0);
|
||||
// expect(event.name).to.equal(EVENT_NAME);
|
||||
// expect(event.description).to.equal(EVENT_DESCRIPTION);
|
||||
// expect(event.capacity).to.equal(EVENT_CAPACITY);
|
||||
// expect(event.ticketPrice).to.equal(EVENT_TICKET_PRICE);
|
||||
// expect(event.eventDate).to.equal(EVENT_DATE);
|
||||
// expect(event.eventHost).to.equal(owner.address);
|
||||
// });
|
||||
|
||||
it("Should emit EventCreated event", async function () {
|
||||
await expect(await createTestEvent())
|
||||
.to.emit(eventManager, "EventCreated")
|
||||
.withArgs(0, EVENT_NAME, EVENT_DATE);
|
||||
});
|
||||
});
|
||||
// it("Should emit EventCreated event", async function () {
|
||||
// await expect(await createTestEvent())
|
||||
// .to.emit(eventManager, "EventCreated")
|
||||
// .withArgs(0, EVENT_NAME, EVENT_DATE);
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("Ticket Purchase", function () {
|
||||
describe('Ticket Purchase', function () {
|
||||
beforeEach(async function () {
|
||||
await createTestEvent();
|
||||
});
|
||||
|
||||
it("Should allow buying a ticket", async function () {
|
||||
it('Should allow buying a ticket', async function () {
|
||||
const ticketPriceFlare = await eventManager.getEventPriceFlare(0);
|
||||
await expect(eventManager.connect(addr1).buyTicket(0, { value: ticketPriceFlare }))
|
||||
.to.emit(eventManager, "TicketPurchased")
|
||||
await expect(
|
||||
eventManager.connect(addr1).buyTicket(0, { value: ticketPriceFlare })
|
||||
)
|
||||
.to.emit(eventManager, 'TicketPurchased')
|
||||
.withArgs(0, 0, addr1.address, ticketPriceFlare);
|
||||
|
||||
const ticket = await eventManager.tickets(0);
|
||||
@@ -71,61 +73,71 @@ describe("EventManager", function () {
|
||||
expect(ticket.eventId).to.equal(0);
|
||||
});
|
||||
|
||||
it("Should fail if insufficient funds are provided", async function () {
|
||||
it('Should fail if insufficient funds are provided', async function () {
|
||||
const ticketPriceFlare = await eventManager.getEventPriceFlare(0);
|
||||
await expect(
|
||||
eventManager.connect(addr1).buyTicket(0, { value: ticketPriceFlare.sub(1) })
|
||||
).to.be.revertedWith("Insufficient value provided");
|
||||
eventManager
|
||||
.connect(addr1)
|
||||
.buyTicket(0, { value: ticketPriceFlare.sub(1) })
|
||||
).to.be.revertedWith('Insufficient value provided');
|
||||
});
|
||||
});
|
||||
|
||||
describe("Ticket Transfer", function () {
|
||||
describe('Ticket Transfer', function () {
|
||||
beforeEach(async function () {
|
||||
await createTestEvent();
|
||||
const ticketPriceFlare = await eventManager.getEventPriceFlare(0);
|
||||
await eventManager.connect(addr1).buyTicket(0, { value: ticketPriceFlare });
|
||||
await eventManager
|
||||
.connect(addr1)
|
||||
.buyTicket(0, { value: ticketPriceFlare });
|
||||
});
|
||||
|
||||
it("Should allow transferring a ticket", async function () {
|
||||
it('Should allow transferring a ticket', async function () {
|
||||
await expect(eventManager.connect(addr1).transferTicket(0, addr2.address))
|
||||
.to.emit(eventManager, "TicketTransferred")
|
||||
.to.emit(eventManager, 'TicketTransferred')
|
||||
.withArgs(0, addr1.address, addr2.address);
|
||||
|
||||
const ticket = await eventManager.tickets(0);
|
||||
expect(ticket.holder).to.equal(addr2.address);
|
||||
});
|
||||
|
||||
it("Should fail if non-owner tries to transfer", async function () {
|
||||
it('Should fail if non-owner tries to transfer', async function () {
|
||||
await expect(
|
||||
eventManager.connect(addr2).transferTicket(0, addr2.address)
|
||||
).to.be.revertedWith("You do not own this ticket");
|
||||
).to.be.revertedWith('You do not own this ticket');
|
||||
});
|
||||
});
|
||||
|
||||
describe("Ticket Approval and Transfer", function () {
|
||||
describe('Ticket Approval and Transfer', function () {
|
||||
beforeEach(async function () {
|
||||
await createTestEvent();
|
||||
const ticketPriceFlare = await eventManager.getEventPriceFlare(0);
|
||||
await eventManager.connect(addr1).buyTicket(0, { value: ticketPriceFlare });
|
||||
await eventManager
|
||||
.connect(addr1)
|
||||
.buyTicket(0, { value: ticketPriceFlare });
|
||||
});
|
||||
|
||||
it("Should allow approving and transferring a ticket", async function () {
|
||||
await expect(eventManager.connect(addr1).approveTicket(0, addr2.address, true))
|
||||
.to.emit(eventManager, "TicketTransferApproved")
|
||||
it('Should allow approving and transferring a ticket', async function () {
|
||||
await expect(
|
||||
eventManager.connect(addr1).approveTicket(0, addr2.address, true)
|
||||
)
|
||||
.to.emit(eventManager, 'TicketTransferApproved')
|
||||
.withArgs(0, addr1.address, addr2.address);
|
||||
|
||||
await expect(eventManager.connect(addr2).transferTicketFrom(0, addr2.address))
|
||||
.to.emit(eventManager, "TicketTransferred")
|
||||
await expect(
|
||||
eventManager.connect(addr2).transferTicketFrom(0, addr2.address)
|
||||
)
|
||||
.to.emit(eventManager, 'TicketTransferred')
|
||||
.withArgs(0, addr1.address, addr2.address);
|
||||
|
||||
const ticket = await eventManager.tickets(0);
|
||||
expect(ticket.holder).to.equal(addr2.address);
|
||||
});
|
||||
|
||||
it("Should fail if transferring without approval", async function () {
|
||||
it('Should fail if transferring without approval', async function () {
|
||||
await expect(
|
||||
eventManager.connect(addr2).transferTicketFrom(0, addr2.address)
|
||||
).to.be.revertedWith("You are not allowed to transfer this ticket");
|
||||
).to.be.revertedWith('You are not allowed to transfer this ticket');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type * as interface from "./interface";
|
||||
export type { interface };
|
||||
import type * as contractInterface from './interface';
|
||||
export type { contractInterface };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type * as interface from "./interface";
|
||||
export type { interface };
|
||||
import type * as interfaces from './interface';
|
||||
export type { interfaces };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type * as interface from "./interface";
|
||||
export type { interface };
|
||||
import type * as interfaces from './interface';
|
||||
export type { interfaces };
|
||||
|
||||
@@ -13,169 +13,237 @@ import type {
|
||||
PopulatedTransaction,
|
||||
Signer,
|
||||
utils,
|
||||
} from "ethers";
|
||||
import type { FunctionFragment, Result } from "@ethersproject/abi";
|
||||
import type { Listener, Provider } from "@ethersproject/providers";
|
||||
} from 'ethers';
|
||||
import type {
|
||||
FunctionFragment,
|
||||
Result,
|
||||
EventFragment,
|
||||
} from '@ethersproject/abi';
|
||||
import type { Listener, Provider } from '@ethersproject/providers';
|
||||
import type {
|
||||
TypedEventFilter,
|
||||
TypedEvent,
|
||||
TypedListener,
|
||||
OnEvent,
|
||||
PromiseOrValue,
|
||||
} from "../common";
|
||||
} from '../common';
|
||||
|
||||
export interface EventManagerInterface extends utils.Interface {
|
||||
functions: {
|
||||
"approveTicket(uint256,address,bool)": FunctionFragment;
|
||||
"buyTicket(uint256)": FunctionFragment;
|
||||
"centsToFlare(uint256)": FunctionFragment;
|
||||
"createEvent(string,string,uint256,uint256,uint256,string[])": FunctionFragment;
|
||||
"eventCounter()": FunctionFragment;
|
||||
"events(uint256)": FunctionFragment;
|
||||
"getEventImages(uint256)": FunctionFragment;
|
||||
"getEventPriceFlare(uint256)": FunctionFragment;
|
||||
"getEventTickets(uint256)": FunctionFragment;
|
||||
"power(uint256,int8)": FunctionFragment;
|
||||
"ticketCounter()": FunctionFragment;
|
||||
"tickets(uint256)": FunctionFragment;
|
||||
"transferTicket(uint256,address)": FunctionFragment;
|
||||
"userTickets(address,uint256)": FunctionFragment;
|
||||
'approveTicket(uint256,address,bool)': FunctionFragment;
|
||||
'buyTicket(uint256)': FunctionFragment;
|
||||
'centsToFlare(uint256)': FunctionFragment;
|
||||
'createEvent(string,string,uint256,uint256,uint256,string[])': FunctionFragment;
|
||||
'eventCounter()': FunctionFragment;
|
||||
'events(uint256)': FunctionFragment;
|
||||
'getEventImages(uint256)': FunctionFragment;
|
||||
'getEventPriceFlare(uint256)': FunctionFragment;
|
||||
'getEventTickets(uint256)': FunctionFragment;
|
||||
'ticketCounter()': FunctionFragment;
|
||||
'tickets(uint256)': FunctionFragment;
|
||||
'transferTicket(uint256,address)': FunctionFragment;
|
||||
'transferTicketFrom(uint256,address)': FunctionFragment;
|
||||
'userTickets(address,uint256)': FunctionFragment;
|
||||
};
|
||||
|
||||
getFunction(
|
||||
nameOrSignatureOrTopic:
|
||||
| "approveTicket"
|
||||
| "buyTicket"
|
||||
| "centsToFlare"
|
||||
| "createEvent"
|
||||
| "eventCounter"
|
||||
| "events"
|
||||
| "getEventImages"
|
||||
| "getEventPriceFlare"
|
||||
| "getEventTickets"
|
||||
| "power"
|
||||
| "ticketCounter"
|
||||
| "tickets"
|
||||
| "transferTicket"
|
||||
| "userTickets"
|
||||
| 'approveTicket'
|
||||
| 'buyTicket'
|
||||
| 'centsToFlare'
|
||||
| 'createEvent'
|
||||
| 'eventCounter'
|
||||
| 'events'
|
||||
| 'getEventImages'
|
||||
| 'getEventPriceFlare'
|
||||
| 'getEventTickets'
|
||||
| 'ticketCounter'
|
||||
| 'tickets'
|
||||
| 'transferTicket'
|
||||
| 'transferTicketFrom'
|
||||
| 'userTickets'
|
||||
): FunctionFragment;
|
||||
|
||||
encodeFunctionData(
|
||||
functionFragment: "approveTicket",
|
||||
functionFragment: 'approveTicket',
|
||||
values: [
|
||||
PromiseOrValue<BigNumberish>,
|
||||
PromiseOrValue<string>,
|
||||
PromiseOrValue<boolean>
|
||||
PromiseOrValue<boolean>,
|
||||
]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "buyTicket",
|
||||
functionFragment: 'buyTicket',
|
||||
values: [PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "centsToFlare",
|
||||
functionFragment: 'centsToFlare',
|
||||
values: [PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "createEvent",
|
||||
functionFragment: 'createEvent',
|
||||
values: [
|
||||
PromiseOrValue<string>,
|
||||
PromiseOrValue<string>,
|
||||
PromiseOrValue<BigNumberish>,
|
||||
PromiseOrValue<BigNumberish>,
|
||||
PromiseOrValue<BigNumberish>,
|
||||
PromiseOrValue<string>[]
|
||||
PromiseOrValue<string>[],
|
||||
]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "eventCounter",
|
||||
functionFragment: 'eventCounter',
|
||||
values?: undefined
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "events",
|
||||
functionFragment: 'events',
|
||||
values: [PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "getEventImages",
|
||||
functionFragment: 'getEventImages',
|
||||
values: [PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "getEventPriceFlare",
|
||||
functionFragment: 'getEventPriceFlare',
|
||||
values: [PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "getEventTickets",
|
||||
functionFragment: 'getEventTickets',
|
||||
values: [PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "power",
|
||||
values: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "ticketCounter",
|
||||
functionFragment: 'ticketCounter',
|
||||
values?: undefined
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "tickets",
|
||||
functionFragment: 'tickets',
|
||||
values: [PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "transferTicket",
|
||||
functionFragment: 'transferTicket',
|
||||
values: [PromiseOrValue<BigNumberish>, PromiseOrValue<string>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: "userTickets",
|
||||
functionFragment: 'transferTicketFrom',
|
||||
values: [PromiseOrValue<BigNumberish>, PromiseOrValue<string>]
|
||||
): string;
|
||||
encodeFunctionData(
|
||||
functionFragment: 'userTickets',
|
||||
values: [PromiseOrValue<string>, PromiseOrValue<BigNumberish>]
|
||||
): string;
|
||||
|
||||
decodeFunctionResult(
|
||||
functionFragment: "approveTicket",
|
||||
functionFragment: 'approveTicket',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(functionFragment: "buyTicket", data: BytesLike): Result;
|
||||
decodeFunctionResult(functionFragment: 'buyTicket', data: BytesLike): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "centsToFlare",
|
||||
functionFragment: 'centsToFlare',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "createEvent",
|
||||
functionFragment: 'createEvent',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "eventCounter",
|
||||
functionFragment: 'eventCounter',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(functionFragment: "events", data: BytesLike): Result;
|
||||
decodeFunctionResult(functionFragment: 'events', data: BytesLike): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "getEventImages",
|
||||
functionFragment: 'getEventImages',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "getEventPriceFlare",
|
||||
functionFragment: 'getEventPriceFlare',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "getEventTickets",
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(functionFragment: "power", data: BytesLike): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "ticketCounter",
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(functionFragment: "tickets", data: BytesLike): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "transferTicket",
|
||||
functionFragment: 'getEventTickets',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: "userTickets",
|
||||
functionFragment: 'ticketCounter',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(functionFragment: 'tickets', data: BytesLike): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: 'transferTicket',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: 'transferTicketFrom',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
decodeFunctionResult(
|
||||
functionFragment: 'userTickets',
|
||||
data: BytesLike
|
||||
): Result;
|
||||
|
||||
events: {};
|
||||
events: {
|
||||
'EventCreated(uint256,string,uint256)': EventFragment;
|
||||
'TicketPurchased(uint256,uint256,address,uint256)': EventFragment;
|
||||
'TicketTransferApproved(uint256,address,address)': EventFragment;
|
||||
'TicketTransferred(uint256,address,address)': EventFragment;
|
||||
};
|
||||
|
||||
getEvent(nameOrSignatureOrTopic: 'EventCreated'): EventFragment;
|
||||
getEvent(nameOrSignatureOrTopic: 'TicketPurchased'): EventFragment;
|
||||
getEvent(nameOrSignatureOrTopic: 'TicketTransferApproved'): EventFragment;
|
||||
getEvent(nameOrSignatureOrTopic: 'TicketTransferred'): EventFragment;
|
||||
}
|
||||
|
||||
export interface EventCreatedEventObject {
|
||||
eventId: BigNumber;
|
||||
name: string;
|
||||
eventDate: BigNumber;
|
||||
}
|
||||
export type EventCreatedEvent = TypedEvent<
|
||||
[BigNumber, string, BigNumber],
|
||||
EventCreatedEventObject
|
||||
>;
|
||||
|
||||
export type EventCreatedEventFilter = TypedEventFilter<EventCreatedEvent>;
|
||||
|
||||
export interface TicketPurchasedEventObject {
|
||||
ticketId: BigNumber;
|
||||
eventId: BigNumber;
|
||||
buyer: string;
|
||||
price: BigNumber;
|
||||
}
|
||||
export type TicketPurchasedEvent = TypedEvent<
|
||||
[BigNumber, BigNumber, string, BigNumber],
|
||||
TicketPurchasedEventObject
|
||||
>;
|
||||
|
||||
export type TicketPurchasedEventFilter = TypedEventFilter<TicketPurchasedEvent>;
|
||||
|
||||
export interface TicketTransferApprovedEventObject {
|
||||
ticketId: BigNumber;
|
||||
owner: string;
|
||||
trustee: string;
|
||||
}
|
||||
export type TicketTransferApprovedEvent = TypedEvent<
|
||||
[BigNumber, string, string],
|
||||
TicketTransferApprovedEventObject
|
||||
>;
|
||||
|
||||
export type TicketTransferApprovedEventFilter =
|
||||
TypedEventFilter<TicketTransferApprovedEvent>;
|
||||
|
||||
export interface TicketTransferredEventObject {
|
||||
ticketId: BigNumber;
|
||||
from: string;
|
||||
to: string;
|
||||
}
|
||||
export type TicketTransferredEvent = TypedEvent<
|
||||
[BigNumber, string, string],
|
||||
TicketTransferredEventObject
|
||||
>;
|
||||
|
||||
export type TicketTransferredEventFilter =
|
||||
TypedEventFilter<TicketTransferredEvent>;
|
||||
|
||||
export interface EventManager extends BaseContract {
|
||||
connect(signerOrProvider: Signer | Provider | string): this;
|
||||
attach(addressOrName: string): this;
|
||||
@@ -262,12 +330,6 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: CallOverrides
|
||||
): Promise<[BigNumber[]]>;
|
||||
|
||||
power(
|
||||
base: PromiseOrValue<BigNumberish>,
|
||||
exponent: PromiseOrValue<BigNumberish>,
|
||||
overrides?: CallOverrides
|
||||
): Promise<[BigNumber]>;
|
||||
|
||||
ticketCounter(overrides?: CallOverrides): Promise<[BigNumber]>;
|
||||
|
||||
tickets(
|
||||
@@ -287,6 +349,12 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: Overrides & { from?: PromiseOrValue<string> }
|
||||
): Promise<ContractTransaction>;
|
||||
|
||||
transferTicketFrom(
|
||||
_ticketId: PromiseOrValue<BigNumberish>,
|
||||
_to: PromiseOrValue<string>,
|
||||
overrides?: Overrides & { from?: PromiseOrValue<string> }
|
||||
): Promise<ContractTransaction>;
|
||||
|
||||
userTickets(
|
||||
arg0: PromiseOrValue<string>,
|
||||
arg1: PromiseOrValue<BigNumberish>,
|
||||
@@ -353,12 +421,6 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: CallOverrides
|
||||
): Promise<BigNumber[]>;
|
||||
|
||||
power(
|
||||
base: PromiseOrValue<BigNumberish>,
|
||||
exponent: PromiseOrValue<BigNumberish>,
|
||||
overrides?: CallOverrides
|
||||
): Promise<BigNumber>;
|
||||
|
||||
ticketCounter(overrides?: CallOverrides): Promise<BigNumber>;
|
||||
|
||||
tickets(
|
||||
@@ -378,6 +440,12 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: Overrides & { from?: PromiseOrValue<string> }
|
||||
): Promise<ContractTransaction>;
|
||||
|
||||
transferTicketFrom(
|
||||
_ticketId: PromiseOrValue<BigNumberish>,
|
||||
_to: PromiseOrValue<string>,
|
||||
overrides?: Overrides & { from?: PromiseOrValue<string> }
|
||||
): Promise<ContractTransaction>;
|
||||
|
||||
userTickets(
|
||||
arg0: PromiseOrValue<string>,
|
||||
arg1: PromiseOrValue<BigNumberish>,
|
||||
@@ -395,7 +463,7 @@ export interface EventManager extends BaseContract {
|
||||
buyTicket(
|
||||
_eventId: PromiseOrValue<BigNumberish>,
|
||||
overrides?: CallOverrides
|
||||
): Promise<void>;
|
||||
): Promise<BigNumber>;
|
||||
|
||||
centsToFlare(
|
||||
_cents: PromiseOrValue<BigNumberish>,
|
||||
@@ -410,7 +478,7 @@ export interface EventManager extends BaseContract {
|
||||
_eventDate: PromiseOrValue<BigNumberish>,
|
||||
_images: PromiseOrValue<string>[],
|
||||
overrides?: CallOverrides
|
||||
): Promise<void>;
|
||||
): Promise<BigNumber>;
|
||||
|
||||
eventCounter(overrides?: CallOverrides): Promise<BigNumber>;
|
||||
|
||||
@@ -444,12 +512,6 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: CallOverrides
|
||||
): Promise<BigNumber[]>;
|
||||
|
||||
power(
|
||||
base: PromiseOrValue<BigNumberish>,
|
||||
exponent: PromiseOrValue<BigNumberish>,
|
||||
overrides?: CallOverrides
|
||||
): Promise<BigNumber>;
|
||||
|
||||
ticketCounter(overrides?: CallOverrides): Promise<BigNumber>;
|
||||
|
||||
tickets(
|
||||
@@ -469,6 +531,12 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: CallOverrides
|
||||
): Promise<void>;
|
||||
|
||||
transferTicketFrom(
|
||||
_ticketId: PromiseOrValue<BigNumberish>,
|
||||
_to: PromiseOrValue<string>,
|
||||
overrides?: CallOverrides
|
||||
): Promise<void>;
|
||||
|
||||
userTickets(
|
||||
arg0: PromiseOrValue<string>,
|
||||
arg1: PromiseOrValue<BigNumberish>,
|
||||
@@ -476,7 +544,53 @@ export interface EventManager extends BaseContract {
|
||||
): Promise<BigNumber>;
|
||||
};
|
||||
|
||||
filters: {};
|
||||
filters: {
|
||||
'EventCreated(uint256,string,uint256)'(
|
||||
eventId?: null,
|
||||
name?: null,
|
||||
eventDate?: null
|
||||
): EventCreatedEventFilter;
|
||||
EventCreated(
|
||||
eventId?: null,
|
||||
name?: null,
|
||||
eventDate?: null
|
||||
): EventCreatedEventFilter;
|
||||
|
||||
'TicketPurchased(uint256,uint256,address,uint256)'(
|
||||
ticketId?: null,
|
||||
eventId?: null,
|
||||
buyer?: null,
|
||||
price?: null
|
||||
): TicketPurchasedEventFilter;
|
||||
TicketPurchased(
|
||||
ticketId?: null,
|
||||
eventId?: null,
|
||||
buyer?: null,
|
||||
price?: null
|
||||
): TicketPurchasedEventFilter;
|
||||
|
||||
'TicketTransferApproved(uint256,address,address)'(
|
||||
ticketId?: null,
|
||||
owner?: null,
|
||||
trustee?: null
|
||||
): TicketTransferApprovedEventFilter;
|
||||
TicketTransferApproved(
|
||||
ticketId?: null,
|
||||
owner?: null,
|
||||
trustee?: null
|
||||
): TicketTransferApprovedEventFilter;
|
||||
|
||||
'TicketTransferred(uint256,address,address)'(
|
||||
ticketId?: null,
|
||||
from?: null,
|
||||
to?: null
|
||||
): TicketTransferredEventFilter;
|
||||
TicketTransferred(
|
||||
ticketId?: null,
|
||||
from?: null,
|
||||
to?: null
|
||||
): TicketTransferredEventFilter;
|
||||
};
|
||||
|
||||
estimateGas: {
|
||||
approveTicket(
|
||||
@@ -528,12 +642,6 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: CallOverrides
|
||||
): Promise<BigNumber>;
|
||||
|
||||
power(
|
||||
base: PromiseOrValue<BigNumberish>,
|
||||
exponent: PromiseOrValue<BigNumberish>,
|
||||
overrides?: CallOverrides
|
||||
): Promise<BigNumber>;
|
||||
|
||||
ticketCounter(overrides?: CallOverrides): Promise<BigNumber>;
|
||||
|
||||
tickets(
|
||||
@@ -547,6 +655,12 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: Overrides & { from?: PromiseOrValue<string> }
|
||||
): Promise<BigNumber>;
|
||||
|
||||
transferTicketFrom(
|
||||
_ticketId: PromiseOrValue<BigNumberish>,
|
||||
_to: PromiseOrValue<string>,
|
||||
overrides?: Overrides & { from?: PromiseOrValue<string> }
|
||||
): Promise<BigNumber>;
|
||||
|
||||
userTickets(
|
||||
arg0: PromiseOrValue<string>,
|
||||
arg1: PromiseOrValue<BigNumberish>,
|
||||
@@ -604,12 +718,6 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: CallOverrides
|
||||
): Promise<PopulatedTransaction>;
|
||||
|
||||
power(
|
||||
base: PromiseOrValue<BigNumberish>,
|
||||
exponent: PromiseOrValue<BigNumberish>,
|
||||
overrides?: CallOverrides
|
||||
): Promise<PopulatedTransaction>;
|
||||
|
||||
ticketCounter(overrides?: CallOverrides): Promise<PopulatedTransaction>;
|
||||
|
||||
tickets(
|
||||
@@ -623,6 +731,12 @@ export interface EventManager extends BaseContract {
|
||||
overrides?: Overrides & { from?: PromiseOrValue<string> }
|
||||
): Promise<PopulatedTransaction>;
|
||||
|
||||
transferTicketFrom(
|
||||
_ticketId: PromiseOrValue<BigNumberish>,
|
||||
_to: PromiseOrValue<string>,
|
||||
overrides?: Overrides & { from?: PromiseOrValue<string> }
|
||||
): Promise<PopulatedTransaction>;
|
||||
|
||||
userTickets(
|
||||
arg0: PromiseOrValue<string>,
|
||||
arg1: PromiseOrValue<BigNumberish>,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as interface from "./interface";
|
||||
export * as interfaces from './interface';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as interface from "./interface";
|
||||
export * as interfaces from './interface';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Autogenerated file. Do not edit manually. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export * as interface from "./interface";
|
||||
export * as interfaces from './interface';
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user