-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathAvastarTeleporter.sol
173 lines (149 loc) · 6.47 KB
/
AvastarTeleporter.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
pragma solidity 0.5.14;
import "./ReplicantFactory.sol";
import "./IAvastarMetadata.sol";
/**
* @title AvastarTeleporter
* @author Cliff Hall
* @notice Management of Avastar Primes, Replicants, and Traits
*/
contract AvastarTeleporter is ReplicantFactory {
/**
* @notice Event emitted when a handler is approved to manage Trait replication.
* @param handler the address being approved to Trait replication
* @param primeIds the array of Avastar Prime tokenIds the handler can use
*/
event TraitAccessApproved(address indexed handler, uint256[] primeIds);
/**
* @notice Event emitted when a handler replicates Traits.
* @param handler the address marking the Traits as used
* @param primeId the token id of the Prime supplying the Traits
* @param used the array of flags representing the Primes resulting Trait usage
*/
event TraitsUsed(address indexed handler, uint256 primeId, bool[12] used);
/**
* @notice Event emitted when AvastarMetadata contract address is set
* @param contractAddress the address of the new AvastarMetadata contract
*/
event MetadataContractAddressSet(address contractAddress);
/**
* @notice Address of the AvastarMetadata contract
*/
address private metadataContractAddress;
/**
* @notice Acknowledge contract is `AvastarTeleporter`
* @return always true
*/
function isAvastarTeleporter() external pure returns (bool) {return true;}
/**
* @notice Set the address of the `AvastarMetadata` contract.
* Only invokable by system admin role, when contract is paused and not upgraded.
* If successful, emits an `MetadataContractAddressSet` event.
* @param _address address of AvastarTeleporter contract
*/
function setMetadataContractAddress(address _address)
external onlySysAdmin whenPaused whenNotUpgraded
{
// Cast the candidate contract to the IAvastarMetadata interface
IAvastarMetadata candidateContract = IAvastarMetadata(_address);
// Verify that we have the appropriate address
require(candidateContract.isAvastarMetadata());
// Set the contract address
metadataContractAddress = _address;
// Emit the event
emit MetadataContractAddressSet(_address);
}
/**
* @notice Get the current address of the `AvastarMetadata` contract.
* return contractAddress the address of the `AvastarMetadata` contract
*/
function getMetadataContractAddress()
external view
returns (address contractAddress) {
return metadataContractAddress;
}
/**
* @notice Get token URI for a given Avastar Token ID.
* Reverts if given token id is not a valid Avastar Token ID.
* @param _tokenId the Token ID of a previously minted Avastar Prime or Replicant
* @return uri the Avastar's off-chain JSON metadata URI
*/
function tokenURI(uint _tokenId)
external view
returns (string memory uri)
{
require(_tokenId < avastars.length);
return IAvastarMetadata(metadataContractAddress).tokenURI(_tokenId);
}
/**
* @notice Approve a handler to manage Trait replication for a set of Avastar Primes.
* Accepts up to 256 primes for approval per call.
* Reverts if caller is not owner of all Primes specified.
* Reverts if no Primes are specified.
* Reverts if given handler already has approval for all Primes specified.
* If successful, emits a `TraitAccessApproved` event.
* @param _handler the address approved for Trait access
* @param _primeIds the token ids for which to approve the handler
*/
function approveTraitAccess(address _handler, uint256[] calldata _primeIds)
external
{
require(_primeIds.length > 0 && _primeIds.length <= 256);
uint256 primeId;
bool approvedAtLeast1 = false;
for (uint8 i = 0; i < _primeIds.length; i++) {
primeId = _primeIds[i];
require(primeId < avastars.length);
require(msg.sender == super.ownerOf(primeId), "Must be token owner");
if (traitHandlerByPrimeTokenId[primeId] != _handler) {
traitHandlerByPrimeTokenId[primeId] = _handler;
approvedAtLeast1 = true;
}
}
require(approvedAtLeast1, "No unhandled primes specified");
// Emit the event
emit TraitAccessApproved(_handler, _primeIds);
}
/**
* @notice Mark some or all of an Avastar Prime's traits used.
* Caller must be the token owner OR the approved handler.
* Caller must send all 12 flags with those to be used set to true, the rest to false.
* The position of each flag in the `_traitFlags` array corresponds to a Gene, of which Traits are variations.
* The flag order is: [ SKIN_TONE, HAIR_COLOR, EYE_COLOR, BG_COLOR, BACKDROP, EARS, FACE, NOSE, MOUTH, FACIAL_FEATURE, EYES, HAIR_STYLE ].
* Reverts if no usable traits are indicated.
* If successful, emits a `TraitsUsed` event.
* @param _primeId the token id for the Prime whose Traits are to be used
* @param _traitFlags an array of no more than 12 booleans representing the Traits to be used
*/
function useTraits(uint256 _primeId, bool[12] calldata _traitFlags)
external
{
// Make certain token id is valid
require(_primeId < avastars.length);
// Make certain caller is token owner OR approved handler
require(msg.sender == super.ownerOf(_primeId) || msg.sender == traitHandlerByPrimeTokenId[_primeId],
"Must be token owner or approved handler" );
// Get the Avastar and make sure it's a Prime
Avastar memory avastar = avastars[_primeId];
require(avastar.wave == Wave.PRIME);
// Get the Prime
Prime storage prime = primesByGeneration[uint8(avastar.generation)][avastar.serial];
// Set the flags.
bool usedAtLeast1;
for (uint8 i = 0; i < 12; i++) {
if (_traitFlags.length > i ) {
if ( !prime.replicated[i] && _traitFlags[i] ) {
prime.replicated[i] = true;
usedAtLeast1 = true;
}
} else {
break;
}
}
// Revert if no flags changed
require(usedAtLeast1, "No reusable traits specified");
// Clear trait handler
traitHandlerByPrimeTokenId[_primeId] = address(0);
// Emit the TraitsUsed event
emit TraitsUsed(msg.sender, _primeId, prime.replicated);
}
}