Skip to content

Commit

Permalink
Merge branch 'feature/dependency-funding'
Browse files Browse the repository at this point in the history
  • Loading branch information
jtourkos committed Oct 30, 2023
2 parents 6e766f3 + d61df5f commit f470a1d
Show file tree
Hide file tree
Showing 58 changed files with 5,462 additions and 2,566 deletions.
2 changes: 1 addition & 1 deletion graphql.codegen.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
overwrite: true
schema: 'https://api.thegraph.com/subgraphs/name/gh0stwheel/drips-v02-on-goerli'
schema: 'https://api.studio.thegraph.com/query/47690/drips-v2-on-goerli/version/latest'
generates:
src/DripsSubgraph/generated/graphql-types.ts:
plugins:
Expand Down
2 changes: 1 addition & 1 deletion graphql.config.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
schema: 'https://api.thegraph.com/subgraphs/name/gh0stwheel/drips-v02-on-goerli'
schema: 'https://api.studio.thegraph.com/query/47690/drips-v2-on-goerli/version/latest'
documents: 'src/**/*.{gql,js,ts,jsx,tsx}'
104 changes: 56 additions & 48 deletions src/AddressDriver/AddressDriverClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import type { Provider } from '@ethersproject/providers';
import type { BigNumberish, ContractTransaction, Signer } from 'ethers';
import { ethers, BigNumber, constants } from 'ethers';
import type { DripsReceiverStruct, SplitsReceiverStruct, UserMetadata } from '../common/types';
import type { StreamReceiverStruct, SplitsReceiverStruct, AccountMetadata } from '../common/types';
import {
validateAddress,
validateClientProvider,
validateClientSigner,
validateCollectInput,
validateEmitUserMetadataInput,
validateSetDripsInput,
validateEmitAccountMetadataInput,
validateSetStreamsInput,
validateSplitsReceivers
} from '../common/validators';
import Utils from '../utils';
Expand Down Expand Up @@ -162,20 +162,20 @@ export default class AddressDriverClient {
}

/**
* Returns the user user ID.
* Returns the user ID.
*
* This is the user ID to which the `AddressDriverClient` is linked and manages Drips.
* @returns A `Promise` which resolves to the user ID.
* @throws {@link DripsErrors.signerMissingError} if the provider's signer is missing.
*/
public async getUserId(): Promise<string> {
public async getAccountId(): Promise<string> {
ensureSignerExists(this.#signer);

const signerAddress = await this.#signer.getAddress();

const userId = await this.#driver.calcUserId(signerAddress);
const accountId = await this.#driver.calcAccountId(signerAddress);

return userId.toString();
return accountId.toString();
}

/**
Expand All @@ -184,16 +184,16 @@ export default class AddressDriverClient {
* @returns A `Promise` which resolves to the user ID.
* @throws {@link DripsErrors.addressError} if the `userAddress` address is not valid.
*/
public async getUserIdByAddress(userAddress: string): Promise<string> {
public async getAccountIdByAddress(userAddress: string): Promise<string> {
validateAddress(userAddress);

const userId = await this.#driver.calcUserId(userAddress);
const accountId = await this.#driver.calcAccountId(userAddress);

return userId.toString();
return accountId.toString();
}

/**
* Collects the received and already split funds and transfers them from the `DripsHub` contract to an address.
* Collects the received and already split funds and transfers them from the `Drips` contract to an address.
* @param tokenAddress The ERC20 token address.
*
* It must preserve amounts, so if some amount of tokens is transferred to
Expand All @@ -218,8 +218,8 @@ export default class AddressDriverClient {
/**
* Gives funds to the receiver.
* The receiver can collect them immediately.
* Transfers funds from the user's wallet to the `DripsHub` contract.
* @param receiverUserId The receiver user ID.
* Transfers funds from the user's wallet to the `Drips` contract.
* @param receiverAccountId The receiver user ID.
* @param tokenAddress The ERC20 token address.
*
* It must preserve amounts, so if some amount of tokens is transferred to
Expand All @@ -229,18 +229,22 @@ export default class AddressDriverClient {
* If you use such tokens in the protocol, they can get stuck or lost.
* @param amount The amount to give (in the smallest unit, e.g., Wei). It must be greater than `0`.
* @returns A `Promise` which resolves to the contract transaction.
* @throws {@link DripsErrors.argumentMissingError} if the `receiverUserId` is missing.
* @throws {@link DripsErrors.argumentMissingError} if the `receiverAccountId` is missing.
* @throws {@link DripsErrors.addressError} if the `tokenAddress` is not valid.
* @throws {@link DripsErrors.argumentError} if the `amount` is less than or equal to `0`.
* @throws {@link DripsErrors.signerMissingError} if the provider's signer is missing.
*/
public async give(receiverUserId: string, tokenAddress: string, amount: BigNumberish): Promise<ContractTransaction> {
public async give(
receiverAccountId: string,
tokenAddress: string,
amount: BigNumberish
): Promise<ContractTransaction> {
ensureSignerExists(this.#signer);

if (isNullOrUndefined(receiverUserId)) {
if (isNullOrUndefined(receiverAccountId)) {
throw DripsErrors.argumentMissingError(
`Could not give: '${nameOf({ receiverUserId })}' is missing.`,
nameOf({ receiverUserId })
`Could not give: '${nameOf({ receiverAccountId })}' is missing.`,
nameOf({ receiverAccountId })
);
}

Expand All @@ -254,7 +258,7 @@ export default class AddressDriverClient {
);
}

const tx = await this.#txFactory.give(receiverUserId, tokenAddress, amount);
const tx = await this.#txFactory.give(receiverAccountId, tokenAddress, amount);

return this.#signer.sendTransaction(tx);
}
Expand Down Expand Up @@ -282,7 +286,7 @@ export default class AddressDriverClient {

/**
* Sets a Drips configuration.
* Transfers funds from the user's wallet to the `DripsHub` contract to fulfill the change of the drips balance.
* Transfers funds from the user's wallet to the `Drips` contract to fulfill the change of the drips balance.
* @param {string} tokenAddress The ERC20 token address.
*
* It must preserve amounts, so if some amount of tokens is transferred to
Expand All @@ -293,7 +297,7 @@ export default class AddressDriverClient {
* @param currentReceivers The drips receivers that were set in the last drips update.
* Pass an empty array if this is the first update.
*
* **Tip**: you might want to use `DripsSubgraphClient.getCurrentDripsReceivers` to easily retrieve the list of current receivers.
* **Tip**: you might want to use `DripsSubgraphClient.getCurrentStreamsReceivers` to easily retrieve the list of current receivers.
* @param newReceivers The new drips receivers (max `100`).
* Duplicate receivers are not allowed and will only be processed once.
* Pass an empty array if you want to clear all receivers.
Expand All @@ -306,33 +310,33 @@ export default class AddressDriverClient {
* @throws {@link DripsErrors.addressError} if `tokenAddress` or `transferToAddress` is not valid.
* @throws {@link DripsErrors.argumentMissingError} if any of the required parameters is missing.
* @throws {@link DripsErrors.argumentError} if `currentReceivers`' or `newReceivers`' count exceeds the max allowed drips receivers.
* @throws {@link DripsErrors.dripsReceiverError} if any of the `currentReceivers` or the `newReceivers` is not valid.
* @throws {@link DripsErrors.dripsReceiverConfigError} if any of the receivers' configuration is not valid.
* @throws {@link DripsErrors.streamsReceiverError} if any of the `currentReceivers` or the `newReceivers` is not valid.
* @throws {@link DripsErrors.streamConfigError} if any of the receivers' configuration is not valid.
* @throws {@link DripsErrors.signerMissingError} if the provider's signer is missing.
*/
public async setDrips(
public async setStreams(
tokenAddress: string,
currentReceivers: DripsReceiverStruct[],
newReceivers: DripsReceiverStruct[],
currentReceivers: StreamReceiverStruct[],
newReceivers: StreamReceiverStruct[],
transferToAddress: string,
balanceDelta: BigNumberish = 0
): Promise<ContractTransaction> {
ensureSignerExists(this.#signer);
validateSetDripsInput(
validateSetStreamsInput(
tokenAddress,
currentReceivers?.map((r) => ({
userId: r.userId.toString(),
config: Utils.DripsReceiverConfiguration.fromUint256(BigNumber.from(r.config).toBigInt())
accountId: r.accountId.toString(),
config: Utils.StreamConfiguration.fromUint256(BigNumber.from(r.config).toBigInt())
})),
newReceivers?.map((r) => ({
userId: r.userId.toString(),
config: Utils.DripsReceiverConfiguration.fromUint256(BigNumber.from(r.config).toBigInt())
accountId: r.accountId.toString(),
config: Utils.StreamConfiguration.fromUint256(BigNumber.from(r.config).toBigInt())
})),
transferToAddress,
balanceDelta
);

const tx = await this.#txFactory.setDrips(
const tx = await this.#txFactory.setStreams(
tokenAddress,
currentReceivers,
balanceDelta,
Expand All @@ -348,49 +352,53 @@ export default class AddressDriverClient {
/**
* Emits the user's metadata.
* The key and the value are _not_ standardized by the protocol, it's up to the user to establish and follow conventions to ensure compatibility with the consumers.
* @param userMetadata The list of user metadata. Note that a metadata `key` needs to be 32bytes.
* @param accountMetadata The list of user metadata. Note that a metadata `key` needs to be 32bytes.
*
* @returns A `Promise` which resolves to the contract transaction.
* @throws {@link DripsErrors.argumentError} if any of the metadata entries is not valid.
* @throws {@link DripsErrors.signerMissingError} if the provider's signer is missing.
*/
public async emitUserMetadata(userMetadata: UserMetadata[]): Promise<ContractTransaction> {
public async emitAccountMetadata(accountMetadata: AccountMetadata[]): Promise<ContractTransaction> {
ensureSignerExists(this.#signer);
validateEmitUserMetadataInput(userMetadata);
validateEmitAccountMetadataInput(accountMetadata);

const userMetadataAsBytes = userMetadata.map((m) => Utils.Metadata.createFromStrings(m.key, m.value));
const accountMetadataAsBytes = accountMetadata.map((m) => Utils.Metadata.createFromStrings(m.key, m.value));

const tx = await this.#txFactory.emitUserMetadata(userMetadataAsBytes);
const tx = await this.#txFactory.emitAccountMetadata(accountMetadataAsBytes);

return this.#signer.sendTransaction(tx);
}

/**
* Returns a user's address given a user ID.
* @param userId The user ID.
* @param accountId The user ID.
* @returns The user's address.
*/
public static getUserAddress = (userId: string): string => {
if (!userId || typeof userId !== 'string') {
throw DripsErrors.argumentError(`Could not get user address: : ${userId} is not a valid string.`);
public static getUserAddress = (accountId: string): string => {
if (isNullOrUndefined(accountId)) {
throw DripsErrors.argumentError(`Could not get user address: accountId is missing.`);
}

const userIdAsBn = ethers.BigNumber.from(userId);
const accountIdAsBn = ethers.BigNumber.from(accountId);

if (userIdAsBn.lt(0) || userIdAsBn.gt(ethers.constants.MaxUint256)) {
if (accountIdAsBn.lt(0) || accountIdAsBn.gt(ethers.constants.MaxUint256)) {
throw DripsErrors.argumentError(
`Could not get user address: ${userId} is not a valid positive number within the range of a uint256.`
`Could not get user address: ${accountId} is not a valid positive number within the range of a uint256.`
);
}

const mid64BitsMask = ethers.BigNumber.from(2).pow(64).sub(1).shl(160);
if (Utils.AccountId.getDriver(accountId) === 'address') {
const mid64BitsMask = ethers.BigNumber.from(2).pow(64).sub(1).shl(160);

if (!userIdAsBn.and(mid64BitsMask).isZero()) {
throw DripsErrors.argumentError('Could not get user address: first 64 (after first 32) bits must be 0');
if (!accountIdAsBn.and(mid64BitsMask).isZero()) {
throw DripsErrors.argumentError(
`Could not get user address: ${accountId} is not a valid user ID. The first 64 (after first 32) bits must be 0.`
);
}
}

const mask = ethers.BigNumber.from(2).pow(160).sub(1);
const address = userIdAsBn.and(mask).toHexString();
const address = accountIdAsBn.and(mask).toHexString();

const paddedAddress = ethers.utils.hexZeroPad(address, 20);

Expand Down
Loading

0 comments on commit f470a1d

Please sign in to comment.