diff --git a/src/constants/v2Addrs.ts b/src/constants/v2Addrs.ts index 592d70a..b4e881a 100644 --- a/src/constants/v2Addrs.ts +++ b/src/constants/v2Addrs.ts @@ -53,3 +53,17 @@ export const MULTICALL_ADDRESS: AddressMap = { [ChainId.BUILDNET]: 'AS1yphCWi7gychZWYPpqrKDiGb6ZacRoji8YYMLHtQ2TSuuQFqLC', [ChainId.MAINNET]: 'AS1FJrNBtZ5oXK9y6Wcmiio5AV6rR2UopqqdQWhBH4Fss9JNMySm' } + +/** + * DEX governance SDK + */ + +export const VOTING_ESCROW_ADDRESS: AddressMap = { + [ChainId.BUILDNET]: '', + [ChainId.MAINNET]: 'AS1q76iSMJ8Dj5gVBVK26y11yuFi9eVzUmTzwf5ANgoypMVcNjXj' +} + +export const VOTER_ADDRESS: AddressMap = { + [ChainId.BUILDNET]: '', + [ChainId.MAINNET]: 'AS1rg37d1cFXrSXbEaKbGPBKRXahshk6VgvwJXjg48MbyuwM1ea6' +} diff --git a/src/contracts/ve.ts b/src/contracts/ve.ts new file mode 100644 index 0000000..a83f768 --- /dev/null +++ b/src/contracts/ve.ts @@ -0,0 +1,179 @@ +import { GlobalPoint, LockedBalance, UserPoint } from '../types/governance' +import { IBaseContract } from './base' +import { Args, bytesToStr, byteToBool, U64, U256 } from '@massalabs/massa-web3' + +export class IVotingEscrow extends IBaseContract { + async ownerOf(tokenId: number): Promise { + return this.extract(['idToOwner::' + tokenId]).then((r) => { + if (!r[0].length) throw new Error('Not found') + return bytesToStr(r[0]) + }) + } + async balanceOf(user: string): Promise { + return this.extract(['ownerToNFTokenCount::' + user]).then((r) => { + if (!r[0].length) throw new Error('Not found') + return Number(U64.fromBytes(r[0])) + }) + } + async getApproved(tokenId: number): Promise { + return this.extract(['idToApprovals::' + tokenId]).then((r) => { + if (!r[0].length) throw new Error('Not found') + return bytesToStr(r[0]) + }) + } + async isApprovedForAll(owner: string, operator: string): Promise { + return this.extract(['ownerToOperators::' + owner + operator]).then((r) => { + if (!r[0].length) throw new Error('Not found') + return byteToBool(r[0]) + }) + } + async isApprovedOrOwner(spender: string, tokenId: number): Promise { + return this.read({ + targetFunction: 'isApprovedOrOwner', + parameter: new Args() + .addString(spender) + .addU64(BigInt(tokenId)) + .serialize() + }).then((r) => byteToBool(r.value)) + } + + async locked(tokenId: number): Promise { + return this.read({ + targetFunction: 'locked', + parameter: new Args().addU64(BigInt(tokenId)).serialize() + }).then((r) => new LockedBalance().deserialize(r.value).instance) + } + async userPointHistory(tokenId: number, loc: number): Promise { + return this.read({ + targetFunction: 'userPointHistory', + parameter: new Args() + .addU64(BigInt(tokenId)) + .addU64(BigInt(loc)) + .serialize() + }).then((r) => new UserPoint().deserialize(r.value).instance) + } + async pointHistory(loc: number): Promise { + return this.read({ + targetFunction: 'pointHistory', + parameter: new Args().addU64(BigInt(loc)).serialize() + }).then((r) => new GlobalPoint().deserialize(r.value).instance) + } + async balanceOfNFT(tokenId: number): Promise { + return this.read({ + targetFunction: 'balanceOfNFT', + parameter: new Args().addU64(BigInt(tokenId)).serialize() + }).then((r) => U256.fromBytes(r.value)) + } + async balanceOfNFTAt(tokenId: number, timestamp: number): Promise { + return this.read({ + targetFunction: 'balanceOfNFTAt', + parameter: new Args() + .addU64(BigInt(tokenId)) + .addU64(BigInt(timestamp)) + .serialize() + }).then((r) => U256.fromBytes(r.value)) + } + async totalSupply(): Promise { + return this.read({ + targetFunction: 'totalSupply', + parameter: new Args().serialize() + }).then((r) => U256.fromBytes(r.value)) + } + async totalSupplyAt(timestamp: number): Promise { + return this.read({ + targetFunction: 'totalSupplyAt', + parameter: new Args().addU64(BigInt(timestamp)).serialize() + }).then((r) => U256.fromBytes(r.value)) + } + async delegates(tokenId: number): Promise { + return this.read({ + targetFunction: 'delegates', + parameter: new Args().addU64(BigInt(tokenId)).serialize() + }).then((r) => Number(U64.fromBytes(r.value))) + } + + async approve(to: string, tokenId: number): Promise { + return this.call({ + targetFunction: 'approve', + parameter: new Args().addString(to).addU64(BigInt(tokenId)).serialize() + }) + } + async setApprovalForAll( + operator: string, + approved: boolean + ): Promise { + return this.call({ + targetFunction: 'setApprovalForAll', + parameter: new Args().addString(operator).addBool(approved).serialize() + }) + } + async transferFrom( + from: string, + to: string, + tokenId: number + ): Promise { + return this.call({ + targetFunction: 'transferFrom', + parameter: new Args() + .addString(from) + .addString(to) + .addU64(BigInt(tokenId)) + .serialize() + }) + } + + depositFor(tokenId: number, amount: bigint): Promise { + return this.call({ + targetFunction: 'depositFor', + parameter: new Args().addU64(BigInt(tokenId)).addU256(amount).serialize() + }) + } + createLock(amount: bigint, duration: number): Promise { + return this.call({ + targetFunction: 'createLock', + parameter: new Args().addU256(amount).addU64(BigInt(duration)).serialize() + }) + } + increaseAmount(tokenId: number, amount: bigint): Promise { + return this.call({ + targetFunction: 'increaseAmount', + parameter: new Args().addU64(BigInt(tokenId)).addU256(amount).serialize() + }) + } + increaseUnlockTime(tokenId: number, lockDuration: number): Promise { + return this.call({ + targetFunction: 'increaseUnlockTime', + parameter: new Args() + .addU64(BigInt(tokenId)) + .addU64(BigInt(lockDuration)) + .serialize() + }) + } + withdraw(tokenId: number): Promise { + return this.call({ + targetFunction: 'withdraw', + parameter: new Args().addU64(BigInt(tokenId)).serialize() + }) + } + lockPermanent(tokenId: number): Promise { + return this.call({ + targetFunction: 'lockPermanent', + parameter: new Args().addU64(BigInt(tokenId)).serialize() + }) + } + unlockPermanent(tokenId: number): Promise { + return this.call({ + targetFunction: 'unlockPermanent', + parameter: new Args().addU64(BigInt(tokenId)).serialize() + }) + } + delegate(delegator: number, delegatee: number): Promise { + return this.call({ + targetFunction: 'delegate', + parameter: new Args() + .addU64(BigInt(delegator)) + .addU64(BigInt(delegatee)) + .serialize() + }) + } +} diff --git a/src/contracts/voter.ts b/src/contracts/voter.ts new file mode 100644 index 0000000..384736a --- /dev/null +++ b/src/contracts/voter.ts @@ -0,0 +1,16 @@ +import { IBaseContract } from './base' +import { U64 } from '@massalabs/massa-web3' + +export class IVoter extends IBaseContract { + async lastVoted(tokenIds: number[]): Promise { + const bs = tokenIds.map((id: number) => `lastVoted::${id}`) + return this.extract(bs).then((r) => { + const lastVoted: number[] = [] + r.forEach((item) => { + if (!item?.length) return + lastVoted.push(Number(U64.fromBytes(item))) + }) + return lastVoted + }) + } +} diff --git a/src/types/governance.ts b/src/types/governance.ts new file mode 100644 index 0000000..b245b74 --- /dev/null +++ b/src/types/governance.ts @@ -0,0 +1,119 @@ +import { Args, IDeserializedResult, ISerializable } from '@massalabs/massa-web3' + +export class Checkpoint implements ISerializable { + constructor( + public fromTimestamp: number = 0, + public owner: string = '', + public delegatedBalance: bigint = 0n, + public delegatee: number = 0 + ) {} + + serialize(): Uint8Array { + return new Args() + .addU64(BigInt(this.fromTimestamp)) + .addString(this.owner) + .addU256(this.delegatedBalance) + .addU64(BigInt(this.delegatee)) + .serialize() + } + + deserialize(data: Uint8Array, offset = 0): IDeserializedResult { + const args = new Args(data, offset) + this.fromTimestamp = Number(args.nextU64()) + this.owner = args.nextString() + this.delegatedBalance = args.nextU256() + this.delegatee = Number(args.nextU64()) + + return { instance: this, offset: args.getOffset() } + } +} + +export class LockedBalance implements ISerializable { + constructor( + public amount: bigint = 0n, + public end: number = 0, + public isPermanent: boolean = false + ) {} + + serialize(): Uint8Array { + return new Args() + .addI128(BigInt(this.amount)) + .addU64(BigInt(this.end)) + .addBool(this.isPermanent) + .serialize() + } + + deserialize( + data: Uint8Array, + offset = 0 + ): IDeserializedResult { + const args = new Args(data, offset) + this.amount = args.nextI128() + this.end = Number(args.nextU64()) + this.isPermanent = args.nextBool() + + return { instance: this, offset: args.getOffset() } + } +} + +export class UserPoint implements ISerializable { + constructor( + public bias: bigint = 0n, + public slope: bigint = 0n, // # -dweight / dt + public ts: number = 0, + public blk: number = 0, // block + public permanent: bigint = 0n + ) {} + + serialize(): Uint8Array { + return new Args() + .addI128(this.bias) + .addI128(this.slope) + .addU64(BigInt(this.ts)) + .addU64(BigInt(this.blk)) + .addU256(this.permanent) + .serialize() + } + + deserialize(data: Uint8Array, offset = 0): IDeserializedResult { + const args = new Args(data, offset) + this.bias = args.nextI128() + this.slope = args.nextI128() + this.ts = Number(args.nextU64()) + this.blk = Number(args.nextU64()) + this.permanent = args.nextU256() + + return { instance: this, offset: args.getOffset() } + } +} + +export class GlobalPoint implements ISerializable { + constructor( + public bias: bigint = 0n, + public slope: bigint = 0n, // # -dweight / dt + public ts: number = 0, + public blk: number = 0, // block + public permanentLockBalance: bigint = 0n + ) {} + + serialize(): Uint8Array { + return new Args() + .addI128(this.bias) + .addI128(this.slope) + .addU64(BigInt(this.ts)) + .addU64(BigInt(this.blk)) + .addU256(this.permanentLockBalance) + .serialize() + } + + deserialize(data: Uint8Array, offset = 0): IDeserializedResult { + const args = new Args(data, offset) + this.bias = args.nextI128() + this.slope = args.nextI128() + this.ts = Number(args.nextU64()) + this.blk = Number(args.nextU64()) + this.permanentLockBalance = args.nextU256() + + return { instance: this, offset: args.getOffset() } + } +}