mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
- Added AaveProtocolTestHelpers
This commit is contained in:
parent
82de55fdbf
commit
21e6697eda
32
contracts/misc/AaveProtocolTestHelpers.sol
Normal file
32
contracts/misc/AaveProtocolTestHelpers.sol
Normal file
|
@ -0,0 +1,32 @@
|
|||
pragma solidity ^0.6.8;
|
||||
pragma experimental ABIEncoderV2;
|
||||
import {ILendingPoolAddressesProvider} from "../interfaces/ILendingPoolAddressesProvider.sol";
|
||||
import {LendingPoolCore} from "../lendingpool/LendingPool.sol";
|
||||
import {AToken} from "../tokenization/AToken.sol";
|
||||
|
||||
contract AaveProtocolTestHelpers {
|
||||
struct ATokenData {
|
||||
string symbol;
|
||||
address aTokenAddress;
|
||||
}
|
||||
|
||||
ILendingPoolAddressesProvider public immutable ADDRESSES_PROVIDER;
|
||||
|
||||
constructor(ILendingPoolAddressesProvider addressesProvider) public {
|
||||
ADDRESSES_PROVIDER = addressesProvider;
|
||||
}
|
||||
|
||||
function getAllATokens() external view returns(ATokenData[] memory) {
|
||||
LendingPoolCore core = LendingPoolCore(ADDRESSES_PROVIDER.getLendingPoolCore());
|
||||
address[] memory reserves = core.getReserves();
|
||||
ATokenData[] memory aTokens;
|
||||
for (uint256 i = 0; i < reserves.length; i++) {
|
||||
address aTokenAddress = core.getReserveATokenAddress(reserves[i]);
|
||||
aTokens[i] = ATokenData({
|
||||
symbol: AToken(aTokenAddress).symbol(),
|
||||
aTokenAddress: aTokenAddress
|
||||
});
|
||||
}
|
||||
return aTokens;
|
||||
}
|
||||
}
|
|
@ -33,6 +33,8 @@ import {TokenDistributor} from "../types/TokenDistributor";
|
|||
import {InitializableAdminUpgradeabilityProxy} from "../types/InitializableAdminUpgradeabilityProxy";
|
||||
import {MockFlashLoanReceiver} from "../types/MockFlashLoanReceiver";
|
||||
import {WalletBalanceProvider} from "../types/WalletBalanceProvider";
|
||||
import {AToken} from "../types/AToken";
|
||||
import {AaveProtocolTestHelpers} from "../types/AaveProtocolTestHelpers";
|
||||
|
||||
export const registerContractInJsonDb = async (
|
||||
contractId: string,
|
||||
|
@ -227,6 +229,14 @@ export const deployMockOneSplit = async (tokenToBurn: tEthereumAddress) =>
|
|||
export const deployOneSplitAdapter = async () =>
|
||||
await deployContract<OneSplitAdapter>(eContractid.OneSplitAdapter, []);
|
||||
|
||||
export const deployAaveProtocolTestHelpers = async (
|
||||
addressesProvider: tEthereumAddress
|
||||
) =>
|
||||
await deployContract<AaveProtocolTestHelpers>(
|
||||
eContractid.AaveProtocolTestHelpers,
|
||||
[addressesProvider]
|
||||
);
|
||||
|
||||
export const deployMintableErc20 = async ([name, symbol, decimals]: [
|
||||
string,
|
||||
string,
|
||||
|
@ -395,6 +405,29 @@ export const getPriceOracle = async (address?: tEthereumAddress) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const getAToken = async (address?: tEthereumAddress) => {
|
||||
return await getContract<AToken>(
|
||||
eContractid.AToken,
|
||||
address ||
|
||||
(await getDb().get(`${eContractid.AToken}.${BRE.network.name}`).value())
|
||||
.address
|
||||
);
|
||||
};
|
||||
|
||||
export const getAaveProtocolTestHelpers = async (
|
||||
address?: tEthereumAddress
|
||||
) => {
|
||||
return await getContract<AaveProtocolTestHelpers>(
|
||||
eContractid.AaveProtocolTestHelpers,
|
||||
address ||
|
||||
(
|
||||
await getDb()
|
||||
.get(`${eContractid.AaveProtocolTestHelpers}.${BRE.network.name}`)
|
||||
.value()
|
||||
).address
|
||||
);
|
||||
};
|
||||
|
||||
const linkBytecode = (artifact: Artifact, libraries: any) => {
|
||||
let bytecode = artifact.bytecode;
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ export enum eContractid {
|
|||
InitializableAdminUpgradeabilityProxy = "InitializableAdminUpgradeabilityProxy",
|
||||
MockFlashLoanReceiver = "MockFlashLoanReceiver",
|
||||
WalletBalanceProvider = "WalletBalanceProvider",
|
||||
AToken = "AToken",
|
||||
AaveProtocolTestHelpers = "AaveProtocolTestHelpers",
|
||||
}
|
||||
|
||||
export type tEthereumAddress = string;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import rawBRE from "@nomiclabs/buidler";
|
||||
import {deployMockContract, MockContract} from "ethereum-waffle";
|
||||
import {MockContract} from "ethereum-waffle";
|
||||
import {
|
||||
deployLendingPoolAddressesProvider,
|
||||
deployMintableErc20,
|
||||
|
@ -23,18 +23,17 @@ import {
|
|||
deployTokenDistributor,
|
||||
deployInitializableAdminUpgradeabilityProxy,
|
||||
deployMockFlashLoanReceiver,
|
||||
registerContractInJsonDb,
|
||||
deployWalletBalancerProvider,
|
||||
getFeeProvider,
|
||||
getLendingPoolParametersProvider,
|
||||
getLendingPoolDataProvider,
|
||||
getLendingPoolProxy,
|
||||
insertContractAddressInDb,
|
||||
deployAaveProtocolTestHelpers,
|
||||
} from "../helpers/contracts-helpers";
|
||||
import {LendingPoolAddressesProvider} from "../types/LendingPoolAddressesProvider";
|
||||
import {evmSnapshot} from "../helpers/misc-utils";
|
||||
import {Wallet, ContractTransaction, ethers} from "ethers";
|
||||
import IERC20MintableBurnableArtifact from "../artifacts/IERC20MintableBurnable.json";
|
||||
import {
|
||||
TokenContractId,
|
||||
eContractid,
|
||||
|
@ -66,17 +65,16 @@ import {LendingRateOracle} from "../types/LendingRateOracle";
|
|||
import {LendingPoolCore} from "../types/LendingPoolCore";
|
||||
import {LendingPoolConfigurator} from "../types/LendingPoolConfigurator";
|
||||
|
||||
const deployAllMockTokens = async (
|
||||
deployer: Wallet,
|
||||
useDoppelganger: boolean
|
||||
) => {
|
||||
const deployAllMockTokens = async (deployer: Wallet) => {
|
||||
const tokens: {[symbol: string]: MockContract | MintableErc20} = {};
|
||||
|
||||
for (const tokenSymbol of Object.keys(TokenContractId)) {
|
||||
if (tokenSymbol !== "ETH") {
|
||||
tokens[tokenSymbol] = useDoppelganger
|
||||
? await deployMockContract(deployer, IERC20MintableBurnableArtifact.abi)
|
||||
: await deployMintableErc20([tokenSymbol, tokenSymbol, 18]);
|
||||
tokens[tokenSymbol] = await deployMintableErc20([
|
||||
tokenSymbol,
|
||||
tokenSymbol,
|
||||
18,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,7 +351,7 @@ const buildTestEnv = async (deployer: Wallet, secondaryWallet: Wallet) => {
|
|||
console.time("setup");
|
||||
const lendingPoolManager = deployer.address;
|
||||
|
||||
const mockTokens = await deployAllMockTokens(deployer, false);
|
||||
const mockTokens = await deployAllMockTokens(deployer);
|
||||
|
||||
const addressesProvider = await deployLendingPoolAddressesProvider();
|
||||
await waitForTx(
|
||||
|
@ -613,6 +611,25 @@ const buildTestEnv = async (deployer: Wallet, secondaryWallet: Wallet) => {
|
|||
|
||||
await deployWalletBalancerProvider(addressesProvider.address);
|
||||
|
||||
const testHelpers = await deployAaveProtocolTestHelpers(
|
||||
addressesProvider.address
|
||||
);
|
||||
console.log(testHelpers.address);
|
||||
console.log(
|
||||
"Addresses provider on test helpers: ",
|
||||
await testHelpers.ADDRESSES_PROVIDER()
|
||||
);
|
||||
try {
|
||||
console.log(await testHelpers.getAllATokens());
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
await insertContractAddressInDb(
|
||||
eContractid.AaveProtocolTestHelpers,
|
||||
testHelpers.address
|
||||
);
|
||||
|
||||
await evmSnapshot();
|
||||
|
||||
console.timeEnd("setup");
|
||||
|
|
|
@ -3,59 +3,44 @@ import {expect} from "chai";
|
|||
import {MockProvider} from "ethereum-waffle";
|
||||
import {BuidlerRuntimeEnvironment} from "@nomiclabs/buidler/types";
|
||||
import {LendingPoolAddressesProvider} from "../types/LendingPoolAddressesProvider";
|
||||
import {getLendingPoolAddressesProvider} from "../helpers/contracts-helpers";
|
||||
import {
|
||||
getLendingPoolAddressesProvider,
|
||||
getLendingPoolProxy,
|
||||
getAToken,
|
||||
getAaveProtocolTestHelpers,
|
||||
} from "../helpers/contracts-helpers";
|
||||
import {evmRevert} from "../helpers/misc-utils";
|
||||
|
||||
describe("AToken: Modifiers", () => {
|
||||
const wallets = new MockProvider().getWallets();
|
||||
let BRE: BuidlerRuntimeEnvironment;
|
||||
let _addressesProvider: LendingPoolAddressesProvider;
|
||||
|
||||
before(async () => {
|
||||
await evmRevert("0x1");
|
||||
_addressesProvider = await getLendingPoolAddressesProvider();
|
||||
console.log(await _addressesProvider.getLendingPoolCore());
|
||||
});
|
||||
|
||||
it("Test the accessibility of the LendingPoolAddressesProvider", async () => {});
|
||||
it("Tries to invoke mintOnDeposit", async () => {
|
||||
const testHelpers = await getAaveProtocolTestHelpers();
|
||||
console.log(await testHelpers.ADDRESSES_PROVIDER());
|
||||
console.log(await testHelpers.getAllATokens())
|
||||
// const aDAI = await getAToken(await lendingPool.getReserveConfigurationData())
|
||||
// await expectRevert(
|
||||
// _aDAI.mintOnDeposit(deployer, "1"),
|
||||
// "The caller of this function must be a lending pool"
|
||||
// );
|
||||
});
|
||||
|
||||
// it("Tries to invoke burnOnLiquidation", async () => {
|
||||
// await expectRevert(
|
||||
// _aDAI.burnOnLiquidation(deployer, "1"),
|
||||
// "The caller of this function must be a lending pool"
|
||||
// );
|
||||
// });
|
||||
|
||||
// it("Tries to invoke transferOnLiquidation", async () => {
|
||||
// await expectRevert(
|
||||
// _aDAI.transferOnLiquidation(deployer, users[1], "1"),
|
||||
// "The caller of this function must be a lending pool"
|
||||
// );
|
||||
// });
|
||||
});
|
||||
|
||||
// contract("AToken: Modifiers", async ([deployer, ...users]) => {
|
||||
// let _testEnvProvider: ITestEnvWithoutInstances;
|
||||
// let _aDAI: ATokenInstance;
|
||||
|
||||
// before("Initializing test variables", async () => {
|
||||
// console.time("setup-test");
|
||||
// _testEnvProvider = await testEnvProviderWithoutInstances(artifacts, [
|
||||
// deployer,
|
||||
// ...users,
|
||||
// ]);
|
||||
|
||||
// const {getATokenInstances} = _testEnvProvider;
|
||||
|
||||
// _aDAI = (await getATokenInstances()).aDAI;
|
||||
|
||||
// console.timeEnd("setup-test");
|
||||
// });
|
||||
|
||||
// it("Tries to invoke mintOnDeposit", async () => {
|
||||
// await expectRevert(
|
||||
// _aDAI.mintOnDeposit(deployer, "1"),
|
||||
// "The caller of this function must be a lending pool"
|
||||
// );
|
||||
// });
|
||||
|
||||
// it("Tries to invoke burnOnLiquidation", async () => {
|
||||
// await expectRevert(
|
||||
// _aDAI.burnOnLiquidation(deployer, "1"),
|
||||
// "The caller of this function must be a lending pool"
|
||||
// );
|
||||
// });
|
||||
|
||||
// it("Tries to invoke transferOnLiquidation", async () => {
|
||||
// await expectRevert(
|
||||
// _aDAI.transferOnLiquidation(deployer, users[1], "1"),
|
||||
// "The caller of this function must be a lending pool"
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
import rawBRE from "@nomiclabs/buidler";
|
||||
import {expect} from "chai";
|
||||
import {MockProvider} from "ethereum-waffle";
|
||||
import {BuidlerRuntimeEnvironment} from "@nomiclabs/buidler/types";
|
||||
import {deployLendingPoolAddressesProvider} from "../helpers/contracts-helpers";
|
||||
import {LendingPoolAddressesProvider} from "../types/LendingPoolAddressesProvider";
|
||||
import {createRandomAddress} from "../helpers/misc-utils";
|
||||
import {getLendingPoolAddressesProvider} from "../helpers/contracts-helpers";
|
||||
import {createRandomAddress, evmRevert} from "../helpers/misc-utils";
|
||||
|
||||
describe("LendingPoolAddressesProvider", () => {
|
||||
const wallets = new MockProvider().getWallets();
|
||||
let BRE: BuidlerRuntimeEnvironment;
|
||||
|
||||
before(async () => {
|
||||
BRE = await rawBRE.run("set-bre");
|
||||
await evmRevert("0x1");
|
||||
});
|
||||
|
||||
it("Test the accessibility of the LendingPoolAddressesProvider", async () => {
|
||||
const mockAddress = createRandomAddress();
|
||||
const INVALID_OWNER_REVERT_MSG = "Ownable: caller is not the owner";
|
||||
const addressesProvider = (await deployLendingPoolAddressesProvider()) as LendingPoolAddressesProvider;
|
||||
const addressesProvider = await getLendingPoolAddressesProvider();
|
||||
await addressesProvider.transferOwnership(wallets[1].address);
|
||||
|
||||
for (const contractFunction of [
|
65
types/AaveProtocolTestHelpers.d.ts
vendored
Normal file
65
types/AaveProtocolTestHelpers.d.ts
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* Generated by ts-generator ver. 0.0.8 */
|
||||
/* tslint:disable */
|
||||
|
||||
import { Contract, ContractTransaction, EventFilter, Signer } from "ethers";
|
||||
import { Listener, Provider } from "ethers/providers";
|
||||
import { Arrayish, BigNumber, BigNumberish, Interface } from "ethers/utils";
|
||||
import {
|
||||
TransactionOverrides,
|
||||
TypedEventDescription,
|
||||
TypedFunctionDescription
|
||||
} from ".";
|
||||
|
||||
interface AaveProtocolTestHelpersInterface extends Interface {
|
||||
functions: {
|
||||
ADDRESSES_PROVIDER: TypedFunctionDescription<{ encode([]: []): string }>;
|
||||
|
||||
getAllATokens: TypedFunctionDescription<{ encode([]: []): string }>;
|
||||
};
|
||||
|
||||
events: {};
|
||||
}
|
||||
|
||||
export class AaveProtocolTestHelpers extends Contract {
|
||||
connect(
|
||||
signerOrProvider: Signer | Provider | string
|
||||
): AaveProtocolTestHelpers;
|
||||
attach(addressOrName: string): AaveProtocolTestHelpers;
|
||||
deployed(): Promise<AaveProtocolTestHelpers>;
|
||||
|
||||
on(event: EventFilter | string, listener: Listener): AaveProtocolTestHelpers;
|
||||
once(
|
||||
event: EventFilter | string,
|
||||
listener: Listener
|
||||
): AaveProtocolTestHelpers;
|
||||
addListener(
|
||||
eventName: EventFilter | string,
|
||||
listener: Listener
|
||||
): AaveProtocolTestHelpers;
|
||||
removeAllListeners(eventName: EventFilter | string): AaveProtocolTestHelpers;
|
||||
removeListener(eventName: any, listener: Listener): AaveProtocolTestHelpers;
|
||||
|
||||
interface: AaveProtocolTestHelpersInterface;
|
||||
|
||||
functions: {
|
||||
ADDRESSES_PROVIDER(): Promise<string>;
|
||||
|
||||
getAllATokens(): Promise<
|
||||
{ symbol: string; aTokenAddress: string; 0: string; 1: string }[]
|
||||
>;
|
||||
};
|
||||
|
||||
ADDRESSES_PROVIDER(): Promise<string>;
|
||||
|
||||
getAllATokens(): Promise<
|
||||
{ symbol: string; aTokenAddress: string; 0: string; 1: string }[]
|
||||
>;
|
||||
|
||||
filters: {};
|
||||
|
||||
estimate: {
|
||||
ADDRESSES_PROVIDER(): Promise<BigNumber>;
|
||||
|
||||
getAllATokens(): Promise<BigNumber>;
|
||||
};
|
||||
}
|
101
types/AaveProtocolTestHelpersFactory.ts
Normal file
101
types/AaveProtocolTestHelpersFactory.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* Generated by ts-generator ver. 0.0.8 */
|
||||
/* tslint:disable */
|
||||
|
||||
import { Contract, ContractFactory, Signer } from "ethers";
|
||||
import { Provider } from "ethers/providers";
|
||||
import { UnsignedTransaction } from "ethers/utils/transaction";
|
||||
|
||||
import { TransactionOverrides } from ".";
|
||||
import { AaveProtocolTestHelpers } from "./AaveProtocolTestHelpers";
|
||||
|
||||
export class AaveProtocolTestHelpersFactory extends ContractFactory {
|
||||
constructor(signer?: Signer) {
|
||||
super(_abi, _bytecode, signer);
|
||||
}
|
||||
|
||||
deploy(
|
||||
addressesProvider: string,
|
||||
overrides?: TransactionOverrides
|
||||
): Promise<AaveProtocolTestHelpers> {
|
||||
return super.deploy(addressesProvider, overrides) as Promise<
|
||||
AaveProtocolTestHelpers
|
||||
>;
|
||||
}
|
||||
getDeployTransaction(
|
||||
addressesProvider: string,
|
||||
overrides?: TransactionOverrides
|
||||
): UnsignedTransaction {
|
||||
return super.getDeployTransaction(addressesProvider, overrides);
|
||||
}
|
||||
attach(address: string): AaveProtocolTestHelpers {
|
||||
return super.attach(address) as AaveProtocolTestHelpers;
|
||||
}
|
||||
connect(signer: Signer): AaveProtocolTestHelpersFactory {
|
||||
return super.connect(signer) as AaveProtocolTestHelpersFactory;
|
||||
}
|
||||
static connect(
|
||||
address: string,
|
||||
signerOrProvider: Signer | Provider
|
||||
): AaveProtocolTestHelpers {
|
||||
return new Contract(
|
||||
address,
|
||||
_abi,
|
||||
signerOrProvider
|
||||
) as AaveProtocolTestHelpers;
|
||||
}
|
||||
}
|
||||
|
||||
const _abi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "contract ILendingPoolAddressesProvider",
|
||||
name: "addressesProvider",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "constructor"
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "ADDRESSES_PROVIDER",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "contract ILendingPoolAddressesProvider",
|
||||
name: "",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function"
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "getAllATokens",
|
||||
outputs: [
|
||||
{
|
||||
components: [
|
||||
{
|
||||
internalType: "string",
|
||||
name: "symbol",
|
||||
type: "string"
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "aTokenAddress",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
internalType: "struct AaveProtocolTestHelpers.ATokenData[]",
|
||||
name: "",
|
||||
type: "tuple[]"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function"
|
||||
}
|
||||
];
|
||||
|
||||
const _bytecode =
|
||||
"0x60a060405234801561001057600080fd5b5060405161064338038061064383398101604081905261002f91610044565b60601b6001600160601b031916608052610072565b600060208284031215610055578081fd5b81516001600160a01b038116811461006b578182fd5b9392505050565b60805160601c6105b16100926000398060705280609852506105b16000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80630542975c1461003b578063f561ae4114610059575b600080fd5b61004361006e565b6040516100509190610468565b60405180910390f35b610061610092565b604051610050919061047c565b7f000000000000000000000000000000000000000000000000000000000000000081565b606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ed6ff7606040518163ffffffff1660e01b815260040160206040518083038186803b1580156100ef57600080fd5b505afa158015610103573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610127919061030e565b90506060816001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160006040518083038186803b15801561016457600080fd5b505afa158015610178573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101a09190810190610331565b9050606060005b82518110156102f5576000846001600160a01b03166334b3beee8584815181106101cd57fe5b60200260200101516040518263ffffffff1660e01b81526004016101f19190610468565b60206040518083038186803b15801561020957600080fd5b505afa15801561021d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610241919061030e565b90506040518060400160405280826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561028757600080fd5b505afa15801561029b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c391908101906103dc565b8152602001826001600160a01b03168152508383815181106102e157fe5b6020908102919091010152506001016101a7565b509250505090565b805161030881610563565b92915050565b60006020828403121561031f578081fd5b815161032a81610563565b9392505050565b60006020808385031215610343578182fd5b825167ffffffffffffffff8082111561035a578384fd5b81850186601f82011261036b578485fd5b805192508183111561037b578485fd5b838302915061038b84830161050c565b8381528481019082860184840187018a10156103a5578788fd5b8794505b858510156103cf576103bb8a826102fd565b8352600194909401939186019186016103a9565b5098975050505050505050565b6000602082840312156103ed578081fd5b815167ffffffffffffffff80821115610404578283fd5b81840185601f820112610415578384fd5b8051925081831115610425578384fd5b610438601f8401601f191660200161050c565b915082825285602084830101111561044e578384fd5b61045f836020840160208401610533565b50949350505050565b6001600160a01b0391909116815260200190565b60208082528251828201819052600091906040908185019080840286018301878501865b838110156104fe57603f19898403018552815180518785528051808987015260606104d0828289018d8601610533565b928a01516001600160a01b0316868b015296890196601f01601f1916909401019250908601906001016104a0565b509098975050505050505050565b60405181810167ffffffffffffffff8111828210171561052b57600080fd5b604052919050565b60005b8381101561054e578181015183820152602001610536565b8381111561055d576000848401525b50505050565b6001600160a01b038116811461057857600080fd5b5056fea264697066735822122050960433c8f7ac57690ddc920d782498bf0717738735870b68637df5806b8e8f64736f6c63430006080033";
|
Loading…
Reference in New Issue
Block a user