diff --git a/.gitignore b/.gitignore index 1806442..cdf1787 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,4 @@ js/lib /node_modules -js/dist **/wallet.json \ No newline at end of file diff --git a/js/dist/index.d.ts b/js/dist/index.d.ts new file mode 100644 index 0000000..803381a --- /dev/null +++ b/js/dist/index.d.ts @@ -0,0 +1,4 @@ +export * from './instructions'; +export * from './main'; +export * from './state'; +export * from './utils'; diff --git a/js/dist/index.js b/js/dist/index.js new file mode 100644 index 0000000..364520f --- /dev/null +++ b/js/dist/index.js @@ -0,0 +1 @@ +"use strict";var e,r=require("@solana/web3.js"),t=require("@solana/spl-token"),n=require("bn.js"),i=require("bs58");function s(e,t,n,i,s){let o=[Buffer.from(Int8Array.from([0]).buffer),Buffer.concat(s)];const a=Buffer.concat(o),c=[{pubkey:e,isSigner:!1,isWritable:!1},{pubkey:r.SYSVAR_RENT_PUBKEY,isSigner:!1,isWritable:!1},{pubkey:n,isSigner:!0,isWritable:!0},{pubkey:i,isSigner:!1,isWritable:!0}];return new r.TransactionInstruction({keys:c,programId:t,data:a})}function o(e,t,n,i,s,o,a,c,u,f){let l=[Buffer.from(Int8Array.from([1]).buffer),Buffer.concat(f),c.toBuffer()];l.push(u.toBuffer());const d=Buffer.concat(l),g=[{pubkey:t,isSigner:!1,isWritable:!1},{pubkey:n,isSigner:!1,isWritable:!1},{pubkey:i,isSigner:!1,isWritable:!0},{pubkey:s,isSigner:!1,isWritable:!0},{pubkey:o,isSigner:!0,isWritable:!1},{pubkey:a,isSigner:!1,isWritable:!0}];return new r.TransactionInstruction({keys:g,programId:e,data:d})}function a(e,t,n,i,s,o,a){const c=Buffer.concat([Buffer.from(Int8Array.from([2]).buffer),Buffer.concat(a)]),u=[{pubkey:t,isSigner:!1,isWritable:!1},{pubkey:n,isSigner:!1,isWritable:!1},{pubkey:i,isSigner:!1,isWritable:!0},{pubkey:s,isSigner:!1,isWritable:!0},{pubkey:o,isSigner:!1,isWritable:!0}];return new r.TransactionInstruction({keys:u,programId:e,data:c})}function c(e,t,n,i,s,o,a){const c=Buffer.concat([Buffer.from(Int8Array.from([3]).buffer),Buffer.concat(a)]),u=[{pubkey:t,isSigner:!1,isWritable:!1},{pubkey:n,isSigner:!1,isWritable:!1},{pubkey:i,isSigner:!1,isWritable:!0},{pubkey:s,isSigner:!1,isWritable:!0},{pubkey:o,isSigner:!1,isWritable:!0}];return new r.TransactionInstruction({keys:u,programId:e,data:c})}exports.Instruction=void 0,(e=exports.Instruction||(exports.Instruction={}))[e.Init=0]="Init",e[e.Create=1]="Create";class u extends n{toBuffer(){const e=super.toArray().reverse(),r=Buffer.from(e);if(8===r.length)return r;if(r.length>8)throw new Error("Numberu64 too large");const t=Buffer.alloc(8);return r.copy(t),t}static fromBuffer(e){if(8!==e.length)throw new Error(`Invalid buffer length: ${e.length}`);return new n([...e].reverse().map((e=>`00${e.toString(16)}`.slice(-2))).join(""),16)}}class f{constructor(e,r){this.timeDelta=e,this.amount=r}toBuffer(){return Buffer.concat([this.timeDelta.toBuffer(),this.amount.toBuffer()])}static fromBuffer(e){const r=u.fromBuffer(e.slice(0,8)),t=u.fromBuffer(e.slice(8,16));return new f(r,t)}}class l{constructor(e,r,t){this.destinationAddress=e,this.mintAddress=r,this.isInitialized=t}static fromBuffer(e){return{destinationAddress:new r.PublicKey(e.slice(0,32)),mintAddress:new r.PublicKey(e.slice(32,64)),isInitialized:1==e[64]}}}class d{constructor(e,r,t){this.destinationAddress=e,this.mintAddress=r,this.schedules=t}static fromBuffer(e){const r=l.fromBuffer(e.slice(0,65));if(!r.isInitialized)return;const t=[];for(let r=65;r4)throw new Error("Numberu32 too large");const t=Buffer.alloc(4);return r.copy(t),t}static fromBuffer(e){if(4!==e.length)throw new Error(`Invalid buffer length: ${e.length}`);return new n([...e].reverse().map((e=>`00${e.toString(16)}`.slice(-2))).join(""),16)}},exports.Numberu64=u,exports.Schedule=f,exports.TOKEN_VESTING_PROGRAM_ID=g,exports.VestingScheduleHeader=l,exports.create=async function(e,n,a,c,u,f,l,d,g){null==f&&(f=await t.getAssociatedTokenAddress(d,u,!0)),a=a.slice(0,31);const[b,p]=await r.PublicKey.findProgramAddress([a],n),m=await t.getAssociatedTokenAddress(d,b,!0);if(a=Buffer.from(a.toString("hex")+p.toString(16),"hex"),console.log("Vesting contract account pubkey: ",b.toBase58()),console.log("contract ID: ",i.encode(a)),await e.getAccountInfo(b))throw"Contract already exists.";return[s(r.SystemProgram.programId,n,c,b,[a]),t.createAssociatedTokenAccountInstruction(c,m,b,d),o(n,t.TOKEN_PROGRAM_ID,r.SYSVAR_CLOCK_PUBKEY,b,m,u,f,d,g,[a])]},exports.createCreateInstruction=o,exports.createInitInstruction=s,exports.createInitializeUnlockInstruction=c,exports.createUnlockInstruction=a,exports.generateRandomSeed=()=>{let e="";for(let r=0;r<64;r++)e+=Math.floor(10*Math.random());return e},exports.getContractInfo=b,exports.initializeUnlock=async function(e,n,i,s){i=i.slice(0,31);const[o,a]=await r.PublicKey.findProgramAddress([i],n);i=Buffer.from(i.toString("hex")+a.toString(16),"hex");const u=await t.getAssociatedTokenAddress(s,o,!0),f=await b(e,o);return[c(n,t.TOKEN_PROGRAM_ID,r.SYSVAR_CLOCK_PUBKEY,o,u,f.destinationAddress,[i])]},exports.unlock=async function(e,n,i,s){i=i.slice(0,31);const[o,c]=await r.PublicKey.findProgramAddress([i],n);i=Buffer.from(i.toString("hex")+c.toString(16),"hex");const u=await t.getAssociatedTokenAddress(s,o,!0),f=await b(e,o);return[a(n,t.TOKEN_PROGRAM_ID,r.SYSVAR_CLOCK_PUBKEY,o,u,f.destinationAddress,[i])]}; diff --git a/js/dist/instructions.d.ts b/js/dist/instructions.d.ts new file mode 100644 index 0000000..c66ac35 --- /dev/null +++ b/js/dist/instructions.d.ts @@ -0,0 +1,11 @@ +/// +import { PublicKey, TransactionInstruction } from '@solana/web3.js'; +import { Schedule } from './state'; +export declare enum Instruction { + Init = 0, + Create = 1 +} +export declare function createInitInstruction(systemProgramId: PublicKey, vestingProgramId: PublicKey, payerKey: PublicKey, vestingAccountKey: PublicKey, seeds: Array): TransactionInstruction; +export declare function createCreateInstruction(vestingProgramId: PublicKey, tokenProgramId: PublicKey, clockSysvarId: PublicKey, vestingAccountKey: PublicKey, vestingTokenAccountKey: PublicKey, sourceTokenAccountOwnerKey: PublicKey, sourceTokenAccountKey: PublicKey, mintAddress: PublicKey, schedule: Schedule, seeds: Array): TransactionInstruction; +export declare function createUnlockInstruction(vestingProgramId: PublicKey, tokenProgramId: PublicKey, clockSysvarId: PublicKey, vestingAccountKey: PublicKey, vestingTokenAccountKey: PublicKey, destinationTokenAccountKey: PublicKey, seeds: Array): TransactionInstruction; +export declare function createInitializeUnlockInstruction(vestingProgramId: PublicKey, tokenProgramId: PublicKey, clockSysvarId: PublicKey, vestingAccountKey: PublicKey, vestingTokenAccountKey: PublicKey, destinationTokenAccountKey: PublicKey, seeds: Array): TransactionInstruction; diff --git a/js/dist/main.d.ts b/js/dist/main.d.ts new file mode 100644 index 0000000..f8e2c5f --- /dev/null +++ b/js/dist/main.d.ts @@ -0,0 +1,46 @@ +/// +import { PublicKey, TransactionInstruction, Connection } from '@solana/web3.js'; +import { ContractInfo, Schedule } from './state'; +/** + * The vesting schedule program ID on mainnet + */ +export declare const TOKEN_VESTING_PROGRAM_ID: PublicKey; +/** + * This function can be used to lock tokens + * @param connection The Solana RPC connection object + * @param programId The token vesting program ID + * @param seedWord Seed words used to derive the vesting account + * @param payer The fee payer of the transaction + * @param sourceTokenOwner The owner of the source token account (i.e where locked tokens are originating from) + * @param possibleSourceTokenPubkey The source token account (i.e where locked tokens are originating from), if null it defaults to the ATA + * @param destinationTokenPubkey The destination token account i.e where unlocked tokens will be transfered + * @param mintAddress The mint of the tokens being vested + * @param schedule The vesting schedule + * @returns An array of `TransactionInstruction` + */ +export declare function create(connection: Connection, programId: PublicKey, seedWord: Buffer | Uint8Array, payer: PublicKey, sourceTokenOwner: PublicKey, possibleSourceTokenPubkey: PublicKey | null, destinationTokenPubkey: PublicKey, mintAddress: PublicKey, schedule: Schedule): Promise>; +/** + * This function can be used to unlock vested tokens + * @param connection The Solana RPC connection object + * @param programId The token vesting program ID + * @param seedWord Seed words used to derive the vesting account + * @param mintAddress The mint of the vested tokens + * @returns An array of `TransactionInstruction` + */ +export declare function unlock(connection: Connection, programId: PublicKey, seedWord: Buffer | Uint8Array, mintAddress: PublicKey): Promise>; +/** + * This function can be used to initialize the unlock of vested tokens + * @param connection The Solana RPC connection object + * @param programId The token vesting program ID + * @param seedWord Seed words used to derive the vesting account + * @param mintAddress The mint of the vested tokens + * @returns An array of `TransactionInstruction` + */ +export declare function initializeUnlock(connection: Connection, programId: PublicKey, seedWord: Buffer | Uint8Array, mintAddress: PublicKey): Promise>; +/** + * This function can be used retrieve information about a vesting account + * @param connection The Solana RPC connection object + * @param vestingAccountKey The vesting account public key + * @returns A `ContractInfo` object + */ +export declare function getContractInfo(connection: Connection, vestingAccountKey: PublicKey): Promise; diff --git a/js/dist/state.d.ts b/js/dist/state.d.ts new file mode 100644 index 0000000..a2571a7 --- /dev/null +++ b/js/dist/state.d.ts @@ -0,0 +1,24 @@ +/// +import { PublicKey } from '@solana/web3.js'; +import { Numberu64 } from './utils'; +export declare class Schedule { + timeDelta: Numberu64; + amount: Numberu64; + constructor(timeDelta: Numberu64, amount: Numberu64); + toBuffer(): Buffer; + static fromBuffer(buf: Buffer): Schedule; +} +export declare class VestingScheduleHeader { + destinationAddress: PublicKey; + mintAddress: PublicKey; + isInitialized: boolean; + constructor(destinationAddress: PublicKey, mintAddress: PublicKey, isInitialized: boolean); + static fromBuffer(buf: Buffer): VestingScheduleHeader; +} +export declare class ContractInfo { + destinationAddress: PublicKey; + mintAddress: PublicKey; + schedules: Array; + constructor(destinationAddress: PublicKey, mintAddress: PublicKey, schedules: Array); + static fromBuffer(buf: Buffer): ContractInfo | undefined; +} diff --git a/js/dist/utils.d.ts b/js/dist/utils.d.ts new file mode 100644 index 0000000..40d952b --- /dev/null +++ b/js/dist/utils.d.ts @@ -0,0 +1,23 @@ +/// +import BN from 'bn.js'; +export declare const generateRandomSeed: () => string; +export declare class Numberu64 extends BN { + /** + * Convert to Buffer representation + */ + toBuffer(): Buffer; + /** + * Construct a Numberu64 from Buffer representation + */ + static fromBuffer(buffer: any): any; +} +export declare class Numberu32 extends BN { + /** + * Convert to Buffer representation + */ + toBuffer(): Buffer; + /** + * Construct a Numberu32 from Buffer representation + */ + static fromBuffer(buffer: any): any; +} diff --git a/js/src/instructions.ts b/js/src/instructions.ts index 61b9d5b..4db40da 100644 --- a/js/src/instructions.ts +++ b/js/src/instructions.ts @@ -59,7 +59,6 @@ export function createCreateInstruction( vestingTokenAccountKey: PublicKey, sourceTokenAccountOwnerKey: PublicKey, sourceTokenAccountKey: PublicKey, - destinationTokenAccountKey: PublicKey, mintAddress: PublicKey, schedule: Schedule, seeds: Array, @@ -68,7 +67,6 @@ export function createCreateInstruction( Buffer.from(Int8Array.from([1]).buffer), Buffer.concat(seeds), mintAddress.toBuffer(), - destinationTokenAccountKey.toBuffer(), ]; buffers.push(schedule.toBuffer()); diff --git a/js/src/main.ts b/js/src/main.ts index 9744815..bad6c69 100644 --- a/js/src/main.ts +++ b/js/src/main.ts @@ -109,7 +109,6 @@ export async function create( vestingTokenAccountKey, sourceTokenOwner, possibleSourceTokenPubkey, - destinationTokenPubkey, mintAddress, schedule, [seedWord], diff --git a/program/src/processor.rs b/program/src/processor.rs index d2bc5a8..b5ac208 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -158,7 +158,7 @@ impl Processor { release_time = clock.unix_timestamp as u64 + schedule.time_delta; } _ => { - msg!("Unsupported time delta"); + msg!("Unsupported time delta: {}", schedule.time_delta); return Err(ProgramError::InvalidInstructionData); } }